@aglyn/plugins-commerce 1.0.0-beta.287 → 1.0.0-beta.288

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@aglyn/plugins-commerce",
3
- "version": "1.0.0-beta.287",
3
+ "version": "1.0.0-beta.288",
4
4
  "license": "Apache-2.0",
5
5
  "homepage": "https://aglyn.com",
6
6
  "repository": {
@@ -25,18 +25,18 @@
25
25
  "./package.json": "./package.json"
26
26
  },
27
27
  "dependencies": {
28
- "@aglyn/aglyn": "1.0.0-beta.287",
29
- "@aglyn/shared-data-mdi": "1.0.0-beta.287",
30
- "@aglyn/shared-ui-jsx": "1.0.0-beta.287",
31
- "@aglyn/shared-ui-next": "1.0.0-beta.287",
32
- "@aglyn/shared-ui-snackstack": "1.0.0-beta.287",
33
- "@aglyn/shared-util-email": "1.0.0-beta.287",
34
- "@aglyn/shared-util-http": "1.0.0-beta.287",
35
- "@aglyn/shared-util-timestamp": "1.0.0-beta.287",
36
- "@aglyn/shared-util-tools": "1.0.0-beta.287",
37
- "@aglyn/tenant-data-admin": "1.0.0-beta.287",
38
- "@aglyn/tenant-feature-instance": "1.0.0-beta.287",
39
- "@aglyn/tenant-runtime": "1.0.0-beta.287",
28
+ "@aglyn/aglyn": "1.0.0-beta.288",
29
+ "@aglyn/shared-data-mdi": "1.0.0-beta.288",
30
+ "@aglyn/shared-ui-jsx": "1.0.0-beta.288",
31
+ "@aglyn/shared-ui-next": "1.0.0-beta.288",
32
+ "@aglyn/shared-ui-snackstack": "1.0.0-beta.288",
33
+ "@aglyn/shared-util-email": "1.0.0-beta.288",
34
+ "@aglyn/shared-util-http": "1.0.0-beta.288",
35
+ "@aglyn/shared-util-timestamp": "1.0.0-beta.288",
36
+ "@aglyn/shared-util-tools": "1.0.0-beta.288",
37
+ "@aglyn/tenant-data-admin": "1.0.0-beta.288",
38
+ "@aglyn/tenant-feature-instance": "1.0.0-beta.288",
39
+ "@aglyn/tenant-runtime": "1.0.0-beta.288",
40
40
  "@stripe/react-stripe-js": "^6.12.0",
41
41
  "@stripe/stripe-js": "^9.17.0",
42
42
  "@swc/helpers": "0.5.23",
@@ -68,7 +68,7 @@ const ROUTE = '/api/commerce/order-webhooks';
68
68
  }).then((payload)=>{
69
69
  if (active) setStatus(payload);
70
70
  }).catch(()=>{
71
- // Not an admin of the whole workspace, or the route is down: the
71
+ // Without "Manage order webhooks" (AGL-4047), or the route is down: the
72
72
  // card is not this person's to use.
73
73
  if (active) setStatus(null);
74
74
  });
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../../../../../../libs/plugins/commerce/src/lib/components/console/order-webhooks-card.component.tsx"],"sourcesContent":["/**\n * @license\n * Copyright 2026 Aglyn LLC\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n'use client'\n\nimport { pluginDocsHelp } from '@aglyn/aglyn'\nimport { CardDisplay, useConfirmationContext } from '@aglyn/shared-ui-jsx'\nimport { ListPagination } from '@aglyn/shared-ui-jsx/components/list-pagination.component'\nimport { useSnackbar } from '@aglyn/shared-ui-snackstack'\nimport { authorizedFetch } from '@aglyn/shared-util-http/authorized-token'\nimport {\n useFirestore,\n useFirestoreCollection,\n usePagedCollection,\n useUser,\n} from '@aglyn/tenant-feature-instance'\nimport {\n Alert,\n Button,\n Checkbox,\n Chip,\n Dialog,\n DialogActions,\n DialogContent,\n DialogTitle,\n FormControlLabel,\n FormGroup,\n MenuItem,\n Stack,\n TextField,\n Typography,\n} from '@mui/material'\nimport { collection, limit, orderBy, query, where } from 'firebase/firestore'\nimport { useCallback, useEffect, useState } from 'react'\nimport * as Webhooks from '../../model/order-webhooks'\n\nexport interface OrderWebhooksCardProps {\n hostId: string\n}\n\ninterface WebhookEventOption {\n event: string\n label: string\n description: string\n}\n\ninterface WebhooksStatus {\n configured: boolean\n maxEndpoints: number\n events: WebhookEventOption[]\n}\n\ntype EndpointRow = Webhooks.OrderWebhookEndpoint & { $id: string }\ntype DeliveryRow = Webhooks.OrderWebhookDelivery & { $id: string }\n\nconst ROUTE = '/api/commerce/order-webhooks'\n\n/** POSTs one action to the webhooks route; answers the body or throws its error. */\nexport async function callOrderWebhooks(\n user: Parameters<typeof authorizedFetch>[0],\n hostId: string,\n body: Record<string, unknown>,\n): Promise<Record<string, any>> {\n const response = await authorizedFetch(user, ROUTE, {\n method: 'POST',\n headers: { 'content-type': 'application/json' },\n body: JSON.stringify({ hostId, ...body }),\n })\n const payload = (await response.json().catch(() => ({}))) as Record<string, any>\n if (!response.ok) throw Object.assign(new Error(String(payload.error ?? 'Request failed')), { status: response.status })\n return payload\n}\n\n/**\n * Order webhooks (AGL-3611): the store's endpoints for order and return\n * events, each with its signing secret, a test event and a delivery log. Shown\n * only to the people who may manage them — the route answers who — and only\n * where the deployment can sign.\n */\nexport function OrderWebhooksCard(props: OrderWebhooksCardProps) {\n const { hostId } = props\n const firestore = useFirestore()\n const { data: user } = useUser()\n const { enqueueSnackbar } = useSnackbar()\n const { confirm } = useConfirmationContext()\n const [status, setStatus] = useState<WebhooksStatus | null>(null)\n const [editing, setEditing] = useState<EndpointRow | 'new' | null>(null)\n const [secret, setSecret] = useState<string | null>(null)\n const [logFor, setLogFor] = useState<EndpointRow | null>(null)\n const [busy, setBusy] = useState(false)\n\n useEffect(() => {\n if (!user) return\n let active = true\n callOrderWebhooks(user, hostId, { action: 'status' })\n .then((payload) => {\n if (active) setStatus(payload as WebhooksStatus)\n })\n .catch(() => {\n // Not an admin of the whole workspace, or the route is down: the\n // card is not this person's to use.\n if (active) setStatus(null)\n })\n return () => {\n active = false\n }\n }, [user, hostId])\n\n const { data: endpointDocs } = useFirestoreCollection<EndpointRow>(\n () =>\n query(\n collection(firestore, 'hosts', hostId, 'orderWebhooks'),\n orderBy('createdAtMs', 'desc'),\n limit(Webhooks.ORDER_WEBHOOK_MAX_ENDPOINTS),\n ),\n [firestore, hostId],\n { idField: '$id' },\n )\n const endpoints = endpointDocs ?? []\n\n const run = useCallback(\n async (body: Record<string, unknown>, success?: string) => {\n setBusy(true)\n try {\n const payload = await callOrderWebhooks(user, hostId, body)\n if (success) enqueueSnackbar(success, { variant: 'success' })\n return payload\n } catch (error) {\n enqueueSnackbar(String((error as Error).message), { variant: 'error' })\n return null\n } finally {\n setBusy(false)\n }\n },\n [user, hostId, enqueueSnackbar],\n )\n\n const handleTest = useCallback(\n async (endpoint: EndpointRow) => {\n const payload = await run({ action: 'test', endpointId: endpoint.$id })\n if (!payload) return\n enqueueSnackbar(\n payload.delivered ? 'Test event delivered' : `Test event not delivered: ${payload.attempt?.error ?? 'no answer'}`,\n { variant: payload.delivered ? 'success' : 'warning' },\n )\n },\n [run, enqueueSnackbar],\n )\n\n const handleRoll = useCallback(\n async (endpoint: EndpointRow) => {\n const confirmed = await confirm({\n title: 'Roll the signing secret?',\n description:\n 'A new secret signs every event from now on. Update your endpoint before ' +\n 'the next order, or it will reject what it is sent.',\n confirmationText: 'Roll secret',\n })\n .then(() => true)\n .catch(() => false)\n if (!confirmed) return\n const payload = await run({ action: 'roll-secret', endpointId: endpoint.$id })\n if (payload?.secret) setSecret(String(payload.secret))\n },\n [confirm, run],\n )\n\n const handleDelete = useCallback(\n async (endpoint: EndpointRow) => {\n const confirmed = await confirm({\n title: 'Delete this endpoint?',\n description: `${endpoint.url} stops receiving order events. Its delivery log is kept for 30 days.`,\n confirmationText: 'Delete',\n confirmationButtonProps: { color: 'error' },\n })\n .then(() => true)\n .catch(() => false)\n if (!confirmed) return\n await run({ action: 'delete', endpointId: endpoint.$id }, 'Endpoint deleted')\n },\n [confirm, run],\n )\n\n if (!status?.configured) return null\n const labelFor = (event: string) => status.events.find((entry) => entry.event === event)?.label ?? event\n const atMax = endpoints.length >= status.maxEndpoints\n\n return (\n <CardDisplay\n header={'Order webhooks'}\n help={pluginDocsHelp('ordersAndReturns', { anchor: '#order-webhooks' })}\n contentGutterX\n contentGutterY\n HeaderProps={{\n action: (\n <Button size=\"small\" disabled={atMax || busy} onClick={() => setEditing('new')}>\n {'Add endpoint'}\n </Button>\n ),\n }}\n >\n <Stack spacing={2}>\n {endpoints.length === 0 ? (\n <Typography variant=\"body2\" color=\"text.secondary\">\n {'Send order and return events to your own systems — a warehouse, an ERP or a ' +\n 'script. Each event is signed so your endpoint can check it came from this store.'}\n </Typography>\n ) : (\n endpoints.map((endpoint) => (\n <Stack key={endpoint.$id} spacing={1} data-testid=\"order-webhook-endpoint\">\n <Stack direction=\"row\" spacing={1} sx={{ alignItems: 'center', flexWrap: 'wrap' }}>\n <Typography variant=\"subtitle2\" sx={{ flex: 1, minWidth: 0, wordBreak: 'break-all' }}>\n {endpoint.description ? `${endpoint.description} · ${endpoint.url}` : endpoint.url}\n </Typography>\n <Chip\n size=\"small\"\n label={endpoint.enabled ? 'On' : 'Paused'}\n color={endpoint.enabled ? 'success' : 'default'}\n variant=\"outlined\"\n />\n {endpoint.lastDeliveryStatus ? (\n <Chip\n size=\"small\"\n label={`Last: ${Webhooks.ORDER_WEBHOOK_DELIVERY_STATUS_LABELS[endpoint.lastDeliveryStatus]}`}\n color={Webhooks.ORDER_WEBHOOK_DELIVERY_STATUS_COLOR[endpoint.lastDeliveryStatus]}\n variant=\"outlined\"\n />\n ) : null}\n </Stack>\n <Typography variant=\"caption\" color=\"text.secondary\">\n {`${endpoint.events.map(labelFor).join(', ')} · secret ends ${endpoint.secretHint}`}\n </Typography>\n <Stack direction=\"row\" spacing={1} sx={{ flexWrap: 'wrap' }}>\n <Button size=\"small\" disabled={busy || !endpoint.enabled} onClick={() => handleTest(endpoint)}>\n {'Send test event'}\n </Button>\n <Button size=\"small\" onClick={() => setLogFor(endpoint)}>\n {'Deliveries'}\n </Button>\n <Button size=\"small\" disabled={busy} onClick={() => setEditing(endpoint)}>\n {'Edit'}\n </Button>\n <Button\n size=\"small\"\n disabled={busy}\n onClick={() => run({ action: 'update', endpointId: endpoint.$id, enabled: !endpoint.enabled })}\n >\n {endpoint.enabled ? 'Pause' : 'Resume'}\n </Button>\n <Button size=\"small\" disabled={busy} onClick={() => handleRoll(endpoint)}>\n {'Roll secret'}\n </Button>\n <Button size=\"small\" color=\"error\" disabled={busy} onClick={() => handleDelete(endpoint)}>\n {'Delete'}\n </Button>\n </Stack>\n </Stack>\n ))\n )}\n <Typography variant=\"caption\" color=\"text.secondary\">\n {`${endpoints.length}/${status.maxEndpoints} endpoints. A failed delivery is retried for about a day.`}\n </Typography>\n </Stack>\n {editing ? (\n <EndpointDialog\n endpoint={editing === 'new' ? null : editing}\n events={status.events}\n busy={busy}\n onClose={() => setEditing(null)}\n onSave={async (values) => {\n const payload =\n editing === 'new'\n ? await run({ action: 'create', ...values })\n : await run({ action: 'update', endpointId: editing.$id, ...values }, 'Endpoint saved')\n if (!payload) return\n setEditing(null)\n if (payload.secret) setSecret(String(payload.secret))\n }}\n />\n ) : null}\n {secret ? <SecretDialog secret={secret} onClose={() => setSecret(null)} /> : null}\n {logFor ? (\n <DeliveriesDialog\n hostId={hostId}\n endpoint={logFor}\n labelFor={labelFor}\n busy={busy}\n onResend={async (delivery) => {\n const payload = await run({ action: 'resend', deliveryId: delivery.$id })\n if (payload) {\n enqueueSnackbar(payload.delivered ? 'Delivered' : `Not delivered: ${payload.attempt?.error ?? 'no answer'}`, {\n variant: payload.delivered ? 'success' : 'warning',\n })\n }\n }}\n onClose={() => setLogFor(null)}\n />\n ) : null}\n </CardDisplay>\n )\n}\nOrderWebhooksCard.displayName = 'OrderWebhooksCard'\n\ninterface EndpointDialogProps {\n endpoint: EndpointRow | null\n events: WebhookEventOption[]\n busy: boolean\n onClose: () => void\n onSave: (values: { url: string; description: string; events: string[] }) => void | Promise<void>\n}\n\nfunction EndpointDialog(props: EndpointDialogProps) {\n const { endpoint, events, busy, onClose, onSave } = props\n const [url, setUrl] = useState(endpoint?.url ?? '')\n const [description, setDescription] = useState(endpoint?.description ?? '')\n const [chosen, setChosen] = useState<string[]>(endpoint?.events ?? events.map((entry) => entry.event))\n const toggle = (event: string) =>\n setChosen((current) => (current.includes(event) ? current.filter((entry) => entry !== event) : [...current, event]))\n const valid = /^https:\\/\\//i.test(url.trim()) && chosen.length > 0\n return (\n <Dialog open onClose={onClose} fullWidth maxWidth=\"sm\">\n <DialogTitle>{endpoint ? 'Edit endpoint' : 'Add endpoint'}</DialogTitle>\n <DialogContent>\n <Stack spacing={2} sx={{ pt: 1 }}>\n <TextField\n label=\"Endpoint URL\"\n value={url}\n onChange={(event) => setUrl(event.target.value)}\n placeholder=\"https://example.com/aglyn-webhooks\"\n helperText=\"An https address on a public server. Redirects are not followed.\"\n fullWidth\n autoFocus\n />\n <TextField\n label=\"Description\"\n value={description}\n onChange={(event) => setDescription(event.target.value)}\n placeholder=\"Warehouse\"\n fullWidth\n />\n <FormGroup>\n <Typography variant=\"subtitle2\">{'Events'}</Typography>\n {events.map((entry) => (\n <FormControlLabel\n key={entry.event}\n control={<Checkbox checked={chosen.includes(entry.event)} onChange={() => toggle(entry.event)} />}\n label={\n <Stack>\n <Typography variant=\"body2\">{`${entry.label} (${entry.event})`}</Typography>\n <Typography variant=\"caption\" color=\"text.secondary\">\n {entry.description}\n </Typography>\n </Stack>\n }\n />\n ))}\n </FormGroup>\n </Stack>\n </DialogContent>\n <DialogActions>\n <Button onClick={onClose}>{'Cancel'}</Button>\n <Button\n variant=\"contained\"\n disabled={!valid || busy}\n onClick={() => onSave({ url: url.trim(), description: description.trim(), events: chosen })}\n >\n {endpoint ? 'Save' : 'Add endpoint'}\n </Button>\n </DialogActions>\n </Dialog>\n )\n}\n\nfunction SecretDialog(props: { secret: string; onClose: () => void }) {\n const { secret, onClose } = props\n const { enqueueSnackbar } = useSnackbar()\n return (\n <Dialog open onClose={onClose} fullWidth maxWidth=\"sm\">\n <DialogTitle>{'Signing secret'}</DialogTitle>\n <DialogContent>\n <Stack spacing={2}>\n <Alert severity=\"warning\">{'Copy it now. It is not shown again; roll a new one if it is lost.'}</Alert>\n <TextField value={secret} fullWidth slotProps={{ input: { readOnly: true } }} label=\"Secret\" />\n <Typography variant=\"body2\" color=\"text.secondary\">\n {`Each request carries an ${Webhooks.ORDER_WEBHOOK_SIGNATURE_HEADER} header, t=<timestamp>,v1=<signature>. ` +\n 'The signature is the HMAC-SHA256, in hex, of the timestamp, a period and the raw body, ' +\n `keyed with this secret. ${Webhooks.ORDER_WEBHOOK_EVENT_ID_HEADER} is the same on every retry.`}\n </Typography>\n </Stack>\n </DialogContent>\n <DialogActions>\n <Button\n onClick={() => {\n void navigator.clipboard\n ?.writeText(secret)\n .then(() => enqueueSnackbar('Secret copied', { variant: 'success' }))\n }}\n >\n {'Copy'}\n </Button>\n <Button variant=\"contained\" onClick={onClose}>\n {'Done'}\n </Button>\n </DialogActions>\n </Dialog>\n )\n}\n\ninterface DeliveriesDialogProps {\n hostId: string\n endpoint: EndpointRow\n labelFor: (event: string) => string\n busy: boolean\n onResend: (delivery: DeliveryRow) => void | Promise<void>\n onClose: () => void\n}\n\n/** The endpoint's delivery log, newest first, filtered and paged by a Firestore query. */\nexport function DeliveriesDialog(props: DeliveriesDialogProps) {\n const { hostId, endpoint, labelFor, busy, onResend, onClose } = props\n const firestore = useFirestore()\n const [statusFilter, setStatusFilter] = useState<Webhooks.OrderWebhookDeliveryStatus | ''>('')\n const [openBody, setOpenBody] = useState<string | null>(null)\n const {\n rows: deliveries,\n hasMore,\n page,\n setPage,\n pageSize,\n setPageSize,\n } = usePagedCollection<DeliveryRow>(\n (pageLimit) =>\n query(\n collection(firestore, 'hosts', hostId, 'orderWebhookDeliveries'),\n where('endpointId', '==', endpoint.$id),\n ...(statusFilter ? [where('status', '==', statusFilter)] : []),\n orderBy('createdAtMs', 'desc'),\n limit(pageLimit),\n ),\n [firestore, hostId, endpoint.$id, statusFilter],\n { idField: '$id' },\n )\n return (\n <Dialog open onClose={onClose} fullWidth maxWidth=\"md\">\n <DialogTitle>{`Deliveries · ${endpoint.url}`}</DialogTitle>\n <DialogContent>\n <Stack spacing={2} sx={{ pt: 1 }}>\n <TextField\n select\n size=\"small\"\n label=\"Status\"\n value={statusFilter}\n onChange={(event) => setStatusFilter(event.target.value as Webhooks.OrderWebhookDeliveryStatus | '')}\n sx={{ maxWidth: 200 }}\n >\n <MenuItem value=\"\">{'All'}</MenuItem>\n {(Object.keys(Webhooks.ORDER_WEBHOOK_DELIVERY_STATUS_LABELS) as Webhooks.OrderWebhookDeliveryStatus[]).map((key) => (\n <MenuItem key={key} value={key}>\n {Webhooks.ORDER_WEBHOOK_DELIVERY_STATUS_LABELS[key]}\n </MenuItem>\n ))}\n </TextField>\n {deliveries.length === 0 ? (\n <Typography variant=\"body2\" color=\"text.secondary\">\n {'No deliveries in the last 30 days.'}\n </Typography>\n ) : (\n deliveries.map((delivery) => {\n const last = delivery.attempts?.[delivery.attempts.length - 1]\n return (\n <Stack key={delivery.$id} spacing={0.5} data-testid=\"order-webhook-delivery\">\n <Stack direction=\"row\" spacing={1} sx={{ alignItems: 'center', flexWrap: 'wrap' }}>\n <Typography variant=\"body2\" sx={{ flex: 1 }}>\n {`${delivery.test ? 'Test event' : labelFor(delivery.event)} · ${new Date(delivery.createdAtMs).toLocaleString()}`}\n </Typography>\n <Chip\n size=\"small\"\n variant=\"outlined\"\n label={Webhooks.ORDER_WEBHOOK_DELIVERY_STATUS_LABELS[delivery.status]}\n color={Webhooks.ORDER_WEBHOOK_DELIVERY_STATUS_COLOR[delivery.status]}\n />\n <Button size=\"small\" onClick={() => setOpenBody(openBody === delivery.$id ? null : delivery.$id)}>\n {openBody === delivery.$id ? 'Hide body' : 'Body'}\n </Button>\n <Button size=\"small\" disabled={busy} onClick={() => onResend(delivery)}>\n {'Resend'}\n </Button>\n </Stack>\n <Typography variant=\"caption\" color=\"text.secondary\">\n {`${delivery.attempts?.length ?? 0} attempt${delivery.attempts?.length === 1 ? '' : 's'}` +\n (last ? ` · last ${last.httpStatus ?? 'no answer'}${last.error ? ` — ${last.error}` : ''}` : '')}\n </Typography>\n {openBody === delivery.$id ? (\n <TextField\n value={delivery.body}\n multiline\n maxRows={12}\n fullWidth\n slotProps={{ input: { readOnly: true } }}\n />\n ) : null}\n </Stack>\n )\n })\n )}\n <ListPagination\n page={page}\n pageSize={pageSize}\n rowCount={deliveries.length}\n hasMore={hasMore}\n onPageChange={setPage}\n onPageSizeChange={setPageSize}\n />\n </Stack>\n </DialogContent>\n <DialogActions>\n <Button onClick={onClose}>{'Close'}</Button>\n </DialogActions>\n </Dialog>\n )\n}\n\nexport default OrderWebhooksCard\n"],"names":["pluginDocsHelp","CardDisplay","useConfirmationContext","ListPagination","useSnackbar","authorizedFetch","useFirestore","useFirestoreCollection","usePagedCollection","useUser","Alert","Button","Checkbox","Chip","Dialog","DialogActions","DialogContent","DialogTitle","FormControlLabel","FormGroup","MenuItem","Stack","TextField","Typography","collection","limit","orderBy","query","where","useCallback","useEffect","useState","Webhooks","ROUTE","callOrderWebhooks","user","hostId","body","payload","response","method","headers","JSON","stringify","json","catch","ok","Object","assign","Error","String","error","status","OrderWebhooksCard","props","firestore","data","enqueueSnackbar","confirm","setStatus","editing","setEditing","secret","setSecret","logFor","setLogFor","busy","setBusy","active","action","then","endpointDocs","ORDER_WEBHOOK_MAX_ENDPOINTS","idField","endpoints","run","success","variant","message","handleTest","endpoint","endpointId","$id","delivered","attempt","handleRoll","confirmed","title","description","confirmationText","handleDelete","url","confirmationButtonProps","color","configured","labelFor","event","events","find","entry","label","atMax","length","maxEndpoints","header","help","anchor","contentGutterX","contentGutterY","HeaderProps","size","disabled","onClick","spacing","map","data-testid","direction","sx","alignItems","flexWrap","flex","minWidth","wordBreak","enabled","lastDeliveryStatus","ORDER_WEBHOOK_DELIVERY_STATUS_LABELS","ORDER_WEBHOOK_DELIVERY_STATUS_COLOR","join","secretHint","EndpointDialog","onClose","onSave","values","SecretDialog","DeliveriesDialog","onResend","delivery","deliveryId","displayName","setUrl","setDescription","chosen","setChosen","toggle","current","includes","filter","valid","test","trim","open","fullWidth","maxWidth","pt","value","onChange","target","placeholder","helperText","autoFocus","control","checked","severity","slotProps","input","readOnly","ORDER_WEBHOOK_SIGNATURE_HEADER","ORDER_WEBHOOK_EVENT_ID_HEADER","navigator","clipboard","writeText","statusFilter","setStatusFilter","openBody","setOpenBody","rows","deliveries","hasMore","page","setPage","pageSize","setPageSize","pageLimit","select","keys","key","last","attempts","Date","createdAtMs","toLocaleString","httpStatus","multiline","maxRows","rowCount","onPageChange","onPageSizeChange"],"mappings":"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"}
1
+ {"version":3,"sources":["../../../../../../../../libs/plugins/commerce/src/lib/components/console/order-webhooks-card.component.tsx"],"sourcesContent":["/**\n * @license\n * Copyright 2026 Aglyn LLC\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n'use client'\n\nimport { pluginDocsHelp } from '@aglyn/aglyn'\nimport { CardDisplay, useConfirmationContext } from '@aglyn/shared-ui-jsx'\nimport { ListPagination } from '@aglyn/shared-ui-jsx/components/list-pagination.component'\nimport { useSnackbar } from '@aglyn/shared-ui-snackstack'\nimport { authorizedFetch } from '@aglyn/shared-util-http/authorized-token'\nimport {\n useFirestore,\n useFirestoreCollection,\n usePagedCollection,\n useUser,\n} from '@aglyn/tenant-feature-instance'\nimport {\n Alert,\n Button,\n Checkbox,\n Chip,\n Dialog,\n DialogActions,\n DialogContent,\n DialogTitle,\n FormControlLabel,\n FormGroup,\n MenuItem,\n Stack,\n TextField,\n Typography,\n} from '@mui/material'\nimport { collection, limit, orderBy, query, where } from 'firebase/firestore'\nimport { useCallback, useEffect, useState } from 'react'\nimport * as Webhooks from '../../model/order-webhooks'\n\nexport interface OrderWebhooksCardProps {\n hostId: string\n}\n\ninterface WebhookEventOption {\n event: string\n label: string\n description: string\n}\n\ninterface WebhooksStatus {\n configured: boolean\n maxEndpoints: number\n events: WebhookEventOption[]\n}\n\ntype EndpointRow = Webhooks.OrderWebhookEndpoint & { $id: string }\ntype DeliveryRow = Webhooks.OrderWebhookDelivery & { $id: string }\n\nconst ROUTE = '/api/commerce/order-webhooks'\n\n/** POSTs one action to the webhooks route; answers the body or throws its error. */\nexport async function callOrderWebhooks(\n user: Parameters<typeof authorizedFetch>[0],\n hostId: string,\n body: Record<string, unknown>,\n): Promise<Record<string, any>> {\n const response = await authorizedFetch(user, ROUTE, {\n method: 'POST',\n headers: { 'content-type': 'application/json' },\n body: JSON.stringify({ hostId, ...body }),\n })\n const payload = (await response.json().catch(() => ({}))) as Record<string, any>\n if (!response.ok) throw Object.assign(new Error(String(payload.error ?? 'Request failed')), { status: response.status })\n return payload\n}\n\n/**\n * Order webhooks (AGL-3611): the store's endpoints for order and return\n * events, each with its signing secret, a test event and a delivery log. Shown\n * only to the people who may manage them — the route answers who — and only\n * where the deployment can sign.\n */\nexport function OrderWebhooksCard(props: OrderWebhooksCardProps) {\n const { hostId } = props\n const firestore = useFirestore()\n const { data: user } = useUser()\n const { enqueueSnackbar } = useSnackbar()\n const { confirm } = useConfirmationContext()\n const [status, setStatus] = useState<WebhooksStatus | null>(null)\n const [editing, setEditing] = useState<EndpointRow | 'new' | null>(null)\n const [secret, setSecret] = useState<string | null>(null)\n const [logFor, setLogFor] = useState<EndpointRow | null>(null)\n const [busy, setBusy] = useState(false)\n\n useEffect(() => {\n if (!user) return\n let active = true\n callOrderWebhooks(user, hostId, { action: 'status' })\n .then((payload) => {\n if (active) setStatus(payload as WebhooksStatus)\n })\n .catch(() => {\n // Without \"Manage order webhooks\" (AGL-4047), or the route is down: the\n // card is not this person's to use.\n if (active) setStatus(null)\n })\n return () => {\n active = false\n }\n }, [user, hostId])\n\n const { data: endpointDocs } = useFirestoreCollection<EndpointRow>(\n () =>\n query(\n collection(firestore, 'hosts', hostId, 'orderWebhooks'),\n orderBy('createdAtMs', 'desc'),\n limit(Webhooks.ORDER_WEBHOOK_MAX_ENDPOINTS),\n ),\n [firestore, hostId],\n { idField: '$id' },\n )\n const endpoints = endpointDocs ?? []\n\n const run = useCallback(\n async (body: Record<string, unknown>, success?: string) => {\n setBusy(true)\n try {\n const payload = await callOrderWebhooks(user, hostId, body)\n if (success) enqueueSnackbar(success, { variant: 'success' })\n return payload\n } catch (error) {\n enqueueSnackbar(String((error as Error).message), { variant: 'error' })\n return null\n } finally {\n setBusy(false)\n }\n },\n [user, hostId, enqueueSnackbar],\n )\n\n const handleTest = useCallback(\n async (endpoint: EndpointRow) => {\n const payload = await run({ action: 'test', endpointId: endpoint.$id })\n if (!payload) return\n enqueueSnackbar(\n payload.delivered ? 'Test event delivered' : `Test event not delivered: ${payload.attempt?.error ?? 'no answer'}`,\n { variant: payload.delivered ? 'success' : 'warning' },\n )\n },\n [run, enqueueSnackbar],\n )\n\n const handleRoll = useCallback(\n async (endpoint: EndpointRow) => {\n const confirmed = await confirm({\n title: 'Roll the signing secret?',\n description:\n 'A new secret signs every event from now on. Update your endpoint before ' +\n 'the next order, or it will reject what it is sent.',\n confirmationText: 'Roll secret',\n })\n .then(() => true)\n .catch(() => false)\n if (!confirmed) return\n const payload = await run({ action: 'roll-secret', endpointId: endpoint.$id })\n if (payload?.secret) setSecret(String(payload.secret))\n },\n [confirm, run],\n )\n\n const handleDelete = useCallback(\n async (endpoint: EndpointRow) => {\n const confirmed = await confirm({\n title: 'Delete this endpoint?',\n description: `${endpoint.url} stops receiving order events. Its delivery log is kept for 30 days.`,\n confirmationText: 'Delete',\n confirmationButtonProps: { color: 'error' },\n })\n .then(() => true)\n .catch(() => false)\n if (!confirmed) return\n await run({ action: 'delete', endpointId: endpoint.$id }, 'Endpoint deleted')\n },\n [confirm, run],\n )\n\n if (!status?.configured) return null\n const labelFor = (event: string) => status.events.find((entry) => entry.event === event)?.label ?? event\n const atMax = endpoints.length >= status.maxEndpoints\n\n return (\n <CardDisplay\n header={'Order webhooks'}\n help={pluginDocsHelp('ordersAndReturns', { anchor: '#order-webhooks' })}\n contentGutterX\n contentGutterY\n HeaderProps={{\n action: (\n <Button size=\"small\" disabled={atMax || busy} onClick={() => setEditing('new')}>\n {'Add endpoint'}\n </Button>\n ),\n }}\n >\n <Stack spacing={2}>\n {endpoints.length === 0 ? (\n <Typography variant=\"body2\" color=\"text.secondary\">\n {'Send order and return events to your own systems — a warehouse, an ERP or a ' +\n 'script. Each event is signed so your endpoint can check it came from this store.'}\n </Typography>\n ) : (\n endpoints.map((endpoint) => (\n <Stack key={endpoint.$id} spacing={1} data-testid=\"order-webhook-endpoint\">\n <Stack direction=\"row\" spacing={1} sx={{ alignItems: 'center', flexWrap: 'wrap' }}>\n <Typography variant=\"subtitle2\" sx={{ flex: 1, minWidth: 0, wordBreak: 'break-all' }}>\n {endpoint.description ? `${endpoint.description} · ${endpoint.url}` : endpoint.url}\n </Typography>\n <Chip\n size=\"small\"\n label={endpoint.enabled ? 'On' : 'Paused'}\n color={endpoint.enabled ? 'success' : 'default'}\n variant=\"outlined\"\n />\n {endpoint.lastDeliveryStatus ? (\n <Chip\n size=\"small\"\n label={`Last: ${Webhooks.ORDER_WEBHOOK_DELIVERY_STATUS_LABELS[endpoint.lastDeliveryStatus]}`}\n color={Webhooks.ORDER_WEBHOOK_DELIVERY_STATUS_COLOR[endpoint.lastDeliveryStatus]}\n variant=\"outlined\"\n />\n ) : null}\n </Stack>\n <Typography variant=\"caption\" color=\"text.secondary\">\n {`${endpoint.events.map(labelFor).join(', ')} · secret ends ${endpoint.secretHint}`}\n </Typography>\n <Stack direction=\"row\" spacing={1} sx={{ flexWrap: 'wrap' }}>\n <Button size=\"small\" disabled={busy || !endpoint.enabled} onClick={() => handleTest(endpoint)}>\n {'Send test event'}\n </Button>\n <Button size=\"small\" onClick={() => setLogFor(endpoint)}>\n {'Deliveries'}\n </Button>\n <Button size=\"small\" disabled={busy} onClick={() => setEditing(endpoint)}>\n {'Edit'}\n </Button>\n <Button\n size=\"small\"\n disabled={busy}\n onClick={() => run({ action: 'update', endpointId: endpoint.$id, enabled: !endpoint.enabled })}\n >\n {endpoint.enabled ? 'Pause' : 'Resume'}\n </Button>\n <Button size=\"small\" disabled={busy} onClick={() => handleRoll(endpoint)}>\n {'Roll secret'}\n </Button>\n <Button size=\"small\" color=\"error\" disabled={busy} onClick={() => handleDelete(endpoint)}>\n {'Delete'}\n </Button>\n </Stack>\n </Stack>\n ))\n )}\n <Typography variant=\"caption\" color=\"text.secondary\">\n {`${endpoints.length}/${status.maxEndpoints} endpoints. A failed delivery is retried for about a day.`}\n </Typography>\n </Stack>\n {editing ? (\n <EndpointDialog\n endpoint={editing === 'new' ? null : editing}\n events={status.events}\n busy={busy}\n onClose={() => setEditing(null)}\n onSave={async (values) => {\n const payload =\n editing === 'new'\n ? await run({ action: 'create', ...values })\n : await run({ action: 'update', endpointId: editing.$id, ...values }, 'Endpoint saved')\n if (!payload) return\n setEditing(null)\n if (payload.secret) setSecret(String(payload.secret))\n }}\n />\n ) : null}\n {secret ? <SecretDialog secret={secret} onClose={() => setSecret(null)} /> : null}\n {logFor ? (\n <DeliveriesDialog\n hostId={hostId}\n endpoint={logFor}\n labelFor={labelFor}\n busy={busy}\n onResend={async (delivery) => {\n const payload = await run({ action: 'resend', deliveryId: delivery.$id })\n if (payload) {\n enqueueSnackbar(payload.delivered ? 'Delivered' : `Not delivered: ${payload.attempt?.error ?? 'no answer'}`, {\n variant: payload.delivered ? 'success' : 'warning',\n })\n }\n }}\n onClose={() => setLogFor(null)}\n />\n ) : null}\n </CardDisplay>\n )\n}\nOrderWebhooksCard.displayName = 'OrderWebhooksCard'\n\ninterface EndpointDialogProps {\n endpoint: EndpointRow | null\n events: WebhookEventOption[]\n busy: boolean\n onClose: () => void\n onSave: (values: { url: string; description: string; events: string[] }) => void | Promise<void>\n}\n\nfunction EndpointDialog(props: EndpointDialogProps) {\n const { endpoint, events, busy, onClose, onSave } = props\n const [url, setUrl] = useState(endpoint?.url ?? '')\n const [description, setDescription] = useState(endpoint?.description ?? '')\n const [chosen, setChosen] = useState<string[]>(endpoint?.events ?? events.map((entry) => entry.event))\n const toggle = (event: string) =>\n setChosen((current) => (current.includes(event) ? current.filter((entry) => entry !== event) : [...current, event]))\n const valid = /^https:\\/\\//i.test(url.trim()) && chosen.length > 0\n return (\n <Dialog open onClose={onClose} fullWidth maxWidth=\"sm\">\n <DialogTitle>{endpoint ? 'Edit endpoint' : 'Add endpoint'}</DialogTitle>\n <DialogContent>\n <Stack spacing={2} sx={{ pt: 1 }}>\n <TextField\n label=\"Endpoint URL\"\n value={url}\n onChange={(event) => setUrl(event.target.value)}\n placeholder=\"https://example.com/aglyn-webhooks\"\n helperText=\"An https address on a public server. Redirects are not followed.\"\n fullWidth\n autoFocus\n />\n <TextField\n label=\"Description\"\n value={description}\n onChange={(event) => setDescription(event.target.value)}\n placeholder=\"Warehouse\"\n fullWidth\n />\n <FormGroup>\n <Typography variant=\"subtitle2\">{'Events'}</Typography>\n {events.map((entry) => (\n <FormControlLabel\n key={entry.event}\n control={<Checkbox checked={chosen.includes(entry.event)} onChange={() => toggle(entry.event)} />}\n label={\n <Stack>\n <Typography variant=\"body2\">{`${entry.label} (${entry.event})`}</Typography>\n <Typography variant=\"caption\" color=\"text.secondary\">\n {entry.description}\n </Typography>\n </Stack>\n }\n />\n ))}\n </FormGroup>\n </Stack>\n </DialogContent>\n <DialogActions>\n <Button onClick={onClose}>{'Cancel'}</Button>\n <Button\n variant=\"contained\"\n disabled={!valid || busy}\n onClick={() => onSave({ url: url.trim(), description: description.trim(), events: chosen })}\n >\n {endpoint ? 'Save' : 'Add endpoint'}\n </Button>\n </DialogActions>\n </Dialog>\n )\n}\n\nfunction SecretDialog(props: { secret: string; onClose: () => void }) {\n const { secret, onClose } = props\n const { enqueueSnackbar } = useSnackbar()\n return (\n <Dialog open onClose={onClose} fullWidth maxWidth=\"sm\">\n <DialogTitle>{'Signing secret'}</DialogTitle>\n <DialogContent>\n <Stack spacing={2}>\n <Alert severity=\"warning\">{'Copy it now. It is not shown again; roll a new one if it is lost.'}</Alert>\n <TextField value={secret} fullWidth slotProps={{ input: { readOnly: true } }} label=\"Secret\" />\n <Typography variant=\"body2\" color=\"text.secondary\">\n {`Each request carries an ${Webhooks.ORDER_WEBHOOK_SIGNATURE_HEADER} header, t=<timestamp>,v1=<signature>. ` +\n 'The signature is the HMAC-SHA256, in hex, of the timestamp, a period and the raw body, ' +\n `keyed with this secret. ${Webhooks.ORDER_WEBHOOK_EVENT_ID_HEADER} is the same on every retry.`}\n </Typography>\n </Stack>\n </DialogContent>\n <DialogActions>\n <Button\n onClick={() => {\n void navigator.clipboard\n ?.writeText(secret)\n .then(() => enqueueSnackbar('Secret copied', { variant: 'success' }))\n }}\n >\n {'Copy'}\n </Button>\n <Button variant=\"contained\" onClick={onClose}>\n {'Done'}\n </Button>\n </DialogActions>\n </Dialog>\n )\n}\n\ninterface DeliveriesDialogProps {\n hostId: string\n endpoint: EndpointRow\n labelFor: (event: string) => string\n busy: boolean\n onResend: (delivery: DeliveryRow) => void | Promise<void>\n onClose: () => void\n}\n\n/** The endpoint's delivery log, newest first, filtered and paged by a Firestore query. */\nexport function DeliveriesDialog(props: DeliveriesDialogProps) {\n const { hostId, endpoint, labelFor, busy, onResend, onClose } = props\n const firestore = useFirestore()\n const [statusFilter, setStatusFilter] = useState<Webhooks.OrderWebhookDeliveryStatus | ''>('')\n const [openBody, setOpenBody] = useState<string | null>(null)\n const {\n rows: deliveries,\n hasMore,\n page,\n setPage,\n pageSize,\n setPageSize,\n } = usePagedCollection<DeliveryRow>(\n (pageLimit) =>\n query(\n collection(firestore, 'hosts', hostId, 'orderWebhookDeliveries'),\n where('endpointId', '==', endpoint.$id),\n ...(statusFilter ? [where('status', '==', statusFilter)] : []),\n orderBy('createdAtMs', 'desc'),\n limit(pageLimit),\n ),\n [firestore, hostId, endpoint.$id, statusFilter],\n { idField: '$id' },\n )\n return (\n <Dialog open onClose={onClose} fullWidth maxWidth=\"md\">\n <DialogTitle>{`Deliveries · ${endpoint.url}`}</DialogTitle>\n <DialogContent>\n <Stack spacing={2} sx={{ pt: 1 }}>\n <TextField\n select\n size=\"small\"\n label=\"Status\"\n value={statusFilter}\n onChange={(event) => setStatusFilter(event.target.value as Webhooks.OrderWebhookDeliveryStatus | '')}\n sx={{ maxWidth: 200 }}\n >\n <MenuItem value=\"\">{'All'}</MenuItem>\n {(Object.keys(Webhooks.ORDER_WEBHOOK_DELIVERY_STATUS_LABELS) as Webhooks.OrderWebhookDeliveryStatus[]).map((key) => (\n <MenuItem key={key} value={key}>\n {Webhooks.ORDER_WEBHOOK_DELIVERY_STATUS_LABELS[key]}\n </MenuItem>\n ))}\n </TextField>\n {deliveries.length === 0 ? (\n <Typography variant=\"body2\" color=\"text.secondary\">\n {'No deliveries in the last 30 days.'}\n </Typography>\n ) : (\n deliveries.map((delivery) => {\n const last = delivery.attempts?.[delivery.attempts.length - 1]\n return (\n <Stack key={delivery.$id} spacing={0.5} data-testid=\"order-webhook-delivery\">\n <Stack direction=\"row\" spacing={1} sx={{ alignItems: 'center', flexWrap: 'wrap' }}>\n <Typography variant=\"body2\" sx={{ flex: 1 }}>\n {`${delivery.test ? 'Test event' : labelFor(delivery.event)} · ${new Date(delivery.createdAtMs).toLocaleString()}`}\n </Typography>\n <Chip\n size=\"small\"\n variant=\"outlined\"\n label={Webhooks.ORDER_WEBHOOK_DELIVERY_STATUS_LABELS[delivery.status]}\n color={Webhooks.ORDER_WEBHOOK_DELIVERY_STATUS_COLOR[delivery.status]}\n />\n <Button size=\"small\" onClick={() => setOpenBody(openBody === delivery.$id ? null : delivery.$id)}>\n {openBody === delivery.$id ? 'Hide body' : 'Body'}\n </Button>\n <Button size=\"small\" disabled={busy} onClick={() => onResend(delivery)}>\n {'Resend'}\n </Button>\n </Stack>\n <Typography variant=\"caption\" color=\"text.secondary\">\n {`${delivery.attempts?.length ?? 0} attempt${delivery.attempts?.length === 1 ? '' : 's'}` +\n (last ? ` · last ${last.httpStatus ?? 'no answer'}${last.error ? ` — ${last.error}` : ''}` : '')}\n </Typography>\n {openBody === delivery.$id ? (\n <TextField\n value={delivery.body}\n multiline\n maxRows={12}\n fullWidth\n slotProps={{ input: { readOnly: true } }}\n />\n ) : null}\n </Stack>\n )\n })\n )}\n <ListPagination\n page={page}\n pageSize={pageSize}\n rowCount={deliveries.length}\n hasMore={hasMore}\n onPageChange={setPage}\n onPageSizeChange={setPageSize}\n />\n </Stack>\n </DialogContent>\n <DialogActions>\n <Button onClick={onClose}>{'Close'}</Button>\n </DialogActions>\n </Dialog>\n )\n}\n\nexport default OrderWebhooksCard\n"],"names":["pluginDocsHelp","CardDisplay","useConfirmationContext","ListPagination","useSnackbar","authorizedFetch","useFirestore","useFirestoreCollection","usePagedCollection","useUser","Alert","Button","Checkbox","Chip","Dialog","DialogActions","DialogContent","DialogTitle","FormControlLabel","FormGroup","MenuItem","Stack","TextField","Typography","collection","limit","orderBy","query","where","useCallback","useEffect","useState","Webhooks","ROUTE","callOrderWebhooks","user","hostId","body","payload","response","method","headers","JSON","stringify","json","catch","ok","Object","assign","Error","String","error","status","OrderWebhooksCard","props","firestore","data","enqueueSnackbar","confirm","setStatus","editing","setEditing","secret","setSecret","logFor","setLogFor","busy","setBusy","active","action","then","endpointDocs","ORDER_WEBHOOK_MAX_ENDPOINTS","idField","endpoints","run","success","variant","message","handleTest","endpoint","endpointId","$id","delivered","attempt","handleRoll","confirmed","title","description","confirmationText","handleDelete","url","confirmationButtonProps","color","configured","labelFor","event","events","find","entry","label","atMax","length","maxEndpoints","header","help","anchor","contentGutterX","contentGutterY","HeaderProps","size","disabled","onClick","spacing","map","data-testid","direction","sx","alignItems","flexWrap","flex","minWidth","wordBreak","enabled","lastDeliveryStatus","ORDER_WEBHOOK_DELIVERY_STATUS_LABELS","ORDER_WEBHOOK_DELIVERY_STATUS_COLOR","join","secretHint","EndpointDialog","onClose","onSave","values","SecretDialog","DeliveriesDialog","onResend","delivery","deliveryId","displayName","setUrl","setDescription","chosen","setChosen","toggle","current","includes","filter","valid","test","trim","open","fullWidth","maxWidth","pt","value","onChange","target","placeholder","helperText","autoFocus","control","checked","severity","slotProps","input","readOnly","ORDER_WEBHOOK_SIGNATURE_HEADER","ORDER_WEBHOOK_EVENT_ID_HEADER","navigator","clipboard","writeText","statusFilter","setStatusFilter","openBody","setOpenBody","rows","deliveries","hasMore","page","setPage","pageSize","setPageSize","pageLimit","select","keys","key","last","attempts","Date","createdAtMs","toLocaleString","httpStatus","multiline","maxRows","rowCount","onPageChange","onPageSizeChange"],"mappings":"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"}
@@ -16,6 +16,7 @@
16
16
  */ import { registerPluginEntitlements } from "@aglyn/aglyn/plugin-manager/plugin-entitlements";
17
17
  import { registerPluginPermissions } from "@aglyn/aglyn/plugin-manager/plugin-permissions";
18
18
  import { COMMERCE_PERMISSIONS, COMMERCE_SITE_PERMISSIONS } from "./model/plugin-permissions.js";
19
+ import { COMMERCE_WORKSPACE_SITE_PERMISSIONS } from "./model/workspace-site-permissions.js";
19
20
  let declared = false;
20
21
  /**
21
22
  * The plugin's DECLARATIONS (AGL-4047): its permission keys (the point of
@@ -32,7 +33,10 @@ let declared = false;
32
33
  declared = true;
33
34
  registerPluginEntitlements({
34
35
  pluginId: 'commerce',
35
- orgPermissions: COMMERCE_SITE_PERMISSIONS
36
+ orgPermissions: [
37
+ ...COMMERCE_SITE_PERMISSIONS,
38
+ ...COMMERCE_WORKSPACE_SITE_PERMISSIONS
39
+ ]
36
40
  });
37
41
  registerPluginPermissions(COMMERCE_PERMISSIONS);
38
42
  }
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../../../../libs/plugins/commerce/src/lib/declarations.ts"],"sourcesContent":["/**\n * @license\n * Copyright 2026 Aglyn LLC\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { registerPluginEntitlements } from '@aglyn/aglyn/plugin-manager/plugin-entitlements'\nimport { registerPluginPermissions } from '@aglyn/aglyn/plugin-manager/plugin-permissions'\nimport { COMMERCE_PERMISSIONS, COMMERCE_SITE_PERMISSIONS } from './model/plugin-permissions'\n\nlet declared = false\n\n/**\n * The plugin's DECLARATIONS (AGL-4047): its permission keys (the point of\n * sale's `managePos` and its finer keys, and the reservation keys whose\n * preset is the site role), which the one permission catalog lists beside\n * the core keys. Loaded eagerly by\n * the console (client and server) and the tenant's server through the\n * generated declarations manifest, so the role editor offers the keys, a\n * custom role or a per-member override keeps them, and a route resolves\n * them whether or not a request has touched the plugin yet. Light by\n * construction: nothing here reaches a provider, Firestore or React.\n */\nexport function registerCommerceDeclarations(): void {\n if (declared) return\n declared = true\n registerPluginEntitlements({ pluginId: 'commerce', orgPermissions: COMMERCE_SITE_PERMISSIONS })\n registerPluginPermissions(COMMERCE_PERMISSIONS)\n}\n\nregisterCommerceDeclarations()\n"],"names":["registerPluginEntitlements","registerPluginPermissions","COMMERCE_PERMISSIONS","COMMERCE_SITE_PERMISSIONS","declared","registerCommerceDeclarations","pluginId","orgPermissions"],"mappings":"AAAA;;;;;;;;;;;;;;;CAeC,GAED,SAASA,0BAA0B,QAAQ,kDAAiD;AAC5F,SAASC,yBAAyB,QAAQ,iDAAgD;AAC1F,SAASC,oBAAoB,EAAEC,yBAAyB,QAAQ,gCAA4B;AAE5F,IAAIC,WAAW;AAEf;;;;;;;;;;CAUC,GACD,OAAO,SAASC;IACd,IAAID,UAAU;IACdA,WAAW;IACXJ,2BAA2B;QAAEM,UAAU;QAAYC,gBAAgBJ;IAA0B;IAC7FF,0BAA0BC;AAC5B;AAEAG"}
1
+ {"version":3,"sources":["../../../../../../libs/plugins/commerce/src/lib/declarations.ts"],"sourcesContent":["/**\n * @license\n * Copyright 2026 Aglyn LLC\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { registerPluginEntitlements } from '@aglyn/aglyn/plugin-manager/plugin-entitlements'\nimport { registerPluginPermissions } from '@aglyn/aglyn/plugin-manager/plugin-permissions'\nimport { COMMERCE_PERMISSIONS, COMMERCE_SITE_PERMISSIONS } from './model/plugin-permissions'\nimport { COMMERCE_WORKSPACE_SITE_PERMISSIONS } from './model/workspace-site-permissions'\n\nlet declared = false\n\n/**\n * The plugin's DECLARATIONS (AGL-4047): its permission keys (the point of\n * sale's `managePos` and its finer keys, and the reservation keys whose\n * preset is the site role), which the one permission catalog lists beside\n * the core keys. Loaded eagerly by\n * the console (client and server) and the tenant's server through the\n * generated declarations manifest, so the role editor offers the keys, a\n * custom role or a per-member override keeps them, and a route resolves\n * them whether or not a request has touched the plugin yet. Light by\n * construction: nothing here reaches a provider, Firestore or React.\n */\nexport function registerCommerceDeclarations(): void {\n if (declared) return\n declared = true\n registerPluginEntitlements({\n pluginId: 'commerce',\n orgPermissions: [...COMMERCE_SITE_PERMISSIONS, ...COMMERCE_WORKSPACE_SITE_PERMISSIONS],\n })\n registerPluginPermissions(COMMERCE_PERMISSIONS)\n}\n\nregisterCommerceDeclarations()\n"],"names":["registerPluginEntitlements","registerPluginPermissions","COMMERCE_PERMISSIONS","COMMERCE_SITE_PERMISSIONS","COMMERCE_WORKSPACE_SITE_PERMISSIONS","declared","registerCommerceDeclarations","pluginId","orgPermissions"],"mappings":"AAAA;;;;;;;;;;;;;;;CAeC,GAED,SAASA,0BAA0B,QAAQ,kDAAiD;AAC5F,SAASC,yBAAyB,QAAQ,iDAAgD;AAC1F,SAASC,oBAAoB,EAAEC,yBAAyB,QAAQ,gCAA4B;AAC5F,SAASC,mCAAmC,QAAQ,wCAAoC;AAExF,IAAIC,WAAW;AAEf;;;;;;;;;;CAUC,GACD,OAAO,SAASC;IACd,IAAID,UAAU;IACdA,WAAW;IACXL,2BAA2B;QACzBO,UAAU;QACVC,gBAAgB;eAAIL;eAA8BC;SAAoC;IACxF;IACAH,0BAA0BC;AAC5B;AAEAI"}
@@ -77,6 +77,13 @@ export declare const ORDERS_SITE_ROLE_PRESET: Readonly<Record<HostAccessRole, bo
77
77
  * whoever works the orders still can).
78
78
  */
79
79
  export declare const STORE_SETTINGS_SITE_ROLE_PRESET: Readonly<Record<HostAccessRole, boolean>>;
80
+ /** The same, per workspace role: the answer with no site named. */
81
+ export declare const STORE_SETTINGS_ORG_ROLE_PRESET: {
82
+ readonly owner: true;
83
+ readonly admin: true;
84
+ readonly editor: false;
85
+ readonly viewer: false;
86
+ };
80
87
  /**
81
88
  * The reservation keys as commerce declares them into the org permission
82
89
  * catalog (AGL-4047), registered beside `COMMERCE_PERMISSIONS`.
@@ -162,7 +162,7 @@
162
162
  author: false,
163
163
  viewer: false
164
164
  };
165
- /** The same, per workspace role: the answer with no site named. */ const STORE_SETTINGS_ORG_ROLE_PRESET = {
165
+ /** The same, per workspace role: the answer with no site named. */ export const STORE_SETTINGS_ORG_ROLE_PRESET = {
166
166
  owner: true,
167
167
  admin: true,
168
168
  editor: false,
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../../../../../libs/plugins/commerce/src/lib/model/plugin-permissions.ts"],"sourcesContent":["/**\n * @license\n * Copyright 2026 Aglyn LLC\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport type { HostAccessRole } from '@aglyn/aglyn/foundation/definitions/organization.types'\nimport type { PluginOrgPermissionDeclaration } from '@aglyn/aglyn/plugin-manager/plugin-entitlements'\nimport type { PluginPermission } from '@aglyn/aglyn/plugin-manager/plugin-permissions'\n\n/**\n * The register's finer permissions (AGL-4047), each a part of `managePos`\n * (Use the point of sale). Each REFINES it: never held without it, and,\n * where no custom role or override sets one, it follows `managePos` — so a\n * member keeps exactly the register they had until somebody narrows it.\n */\nexport type PosRegisterPermission =\n | 'posSell'\n | 'posRefund'\n | 'posDiscount'\n | 'posCashDrawer'\n | 'posDevices'\n\n/**\n * The register's keys and `posBuyHardware`, which stands on its own\n * (AGL-4047): it FOLLOWS `managePos` where no custom role or override sets\n * it, so every member keeps the hardware shop they had, but it may be\n * granted without the register — a bookkeeper who orders the store's readers\n * and never rings a sale.\n */\nexport type PosPermission = PosRegisterPermission | 'posBuyHardware'\n\n/** The tier defaults `managePos` has, which every finer key mirrors. */\nconst POS_TIER_DEFAULTS = { admin: true, editor: true, viewer: false } as const\n\n/*\n * The register is a site's own (AGL-4047): `managePos` and its five finer\n * keys are `narrowsPerSite`, so an editor of the whole workspace given Viewer\n * or Author access to one site does not work that site's register unless the\n * site grants it to them. `posBuyHardware` is not: the hardware shop spends\n * the workspace's money, and its verdict is the workspace's on every site.\n */\n\n/**\n * Commerce's plugin-declared permissions (AGL-435) — the reference\n * adopter. Pure data: the client barrel and /server entry both register\n * it, so console gating and API-side resolution agree.\n */\nexport const COMMERCE_PERMISSIONS: readonly PluginPermission[] = [\n {\n key: 'managePos',\n pluginId: 'commerce',\n label: 'Use the point of sale',\n description:\n 'Open the point of sale. Each point of sale permission below follows this one unless a role or member sets it.',\n defaults: { ...POS_TIER_DEFAULTS },\n groupLabel: 'Commerce',\n narrowsPerSite: true,\n },\n {\n key: 'posSell',\n pluginId: 'commerce',\n label: 'Sell at the register',\n description: 'Ring up sales and take payment at the register, the kiosk and the point of sale apps.',\n defaults: { ...POS_TIER_DEFAULTS },\n groupLabel: 'Commerce',\n narrowsPerSite: true,\n refines: 'managePos',\n },\n {\n key: 'posRefund',\n pluginId: 'commerce',\n label: 'Refunds and returns',\n description: 'Refund point of sale orders at the register, up to its refund limit, and take returns and exchanges.',\n defaults: { ...POS_TIER_DEFAULTS },\n groupLabel: 'Commerce',\n narrowsPerSite: true,\n refines: 'managePos',\n },\n {\n key: 'posDiscount',\n pluginId: 'commerce',\n label: 'Give discounts at the register',\n description:\n 'Take a discount off a sale at the register. A shopper’s discount code and the store’s own promotions apply without it.',\n defaults: { ...POS_TIER_DEFAULTS },\n groupLabel: 'Commerce',\n narrowsPerSite: true,\n refines: 'managePos',\n },\n {\n key: 'posCashDrawer',\n pluginId: 'commerce',\n label: 'Cash drawer and shifts',\n description: 'Open and close shifts, record cash in and out, print shift reports and open the drawer without a sale.',\n defaults: { ...POS_TIER_DEFAULTS },\n groupLabel: 'Commerce',\n narrowsPerSite: true,\n refines: 'managePos',\n },\n {\n key: 'posDevices',\n pluginId: 'commerce',\n label: 'Registers and devices',\n description: 'Add, change and remove card readers, receipt printers and customer displays, and set the reader screen.',\n defaults: { ...POS_TIER_DEFAULTS },\n groupLabel: 'Commerce',\n narrowsPerSite: true,\n refines: 'managePos',\n },\n {\n key: 'posBuyHardware',\n pluginId: 'commerce',\n label: 'Buy point of sale hardware',\n description:\n 'Order card readers and other hardware from the hardware shop. Follows \"Use the point of sale\" unless a role or member sets it, and may be allowed without it.',\n defaults: { ...POS_TIER_DEFAULTS },\n groupLabel: 'Commerce',\n follows: 'managePos',\n },\n]\n\n/** One finer register key's label, for a refusal or a disabled control's reason. */\nexport function posPermissionLabel(permission: PosPermission): string {\n return COMMERCE_PERMISSIONS.find((entry) => entry.key === permission)?.label ?? permission\n}\n\n/**\n * Whether a resolved permission map allows one of the register's finer\n * actions (AGL-4047): `managePos`, and the finer key not refused. A map\n * that does not carry the finer key at all follows `managePos` — the\n * resolvers always carry it once commerce has registered, so an absent key\n * is a map built before that, which keeps the register it had.\n *\n * `posBuyHardware` stands on its own: its own verdict when the map carries\n * one, granted with or without `managePos`, and `managePos`'s when it does\n * not.\n */\nexport function holdsPosPermission(\n permissions: Readonly<Record<string, boolean | undefined>> | null | undefined,\n permission: PosPermission,\n): boolean {\n if (permission === 'posBuyHardware') {\n const own = permissions?.[permission]\n return typeof own === 'boolean' ? own : permissions?.['managePos'] === true\n }\n return permissions?.['managePos'] === true && permissions?.[permission] !== false\n}\n\n/**\n * Whether a member may open the hardware shop at all (AGL-4047): see what\n * it offers and what the store ordered. Whoever works the register, and\n * whoever may buy hardware without working it.\n */\nexport function mayVisitPosHardwareShop(\n permissions: Readonly<Record<string, boolean | undefined>> | null | undefined,\n): boolean {\n return permissions?.['managePos'] === true || holdsPosPermission(permissions, 'posBuyHardware')\n}\n\n/** The refusal a register route answers when a finer key is not held. */\nexport function posPermissionRefusal(permission: PosPermission): string {\n return `Your role does not include \"${posPermissionLabel(permission)}\" — ask an organization admin`\n}\n\n/*\n * RESERVATIONS (AGL-4047).\n *\n * A site's stays and what they book were decided by the member's role ON THE\n * SITE: Admin, Editor and Author could book a walk-in, change a stay's guests\n * and edit or cancel stays, and a Viewer could not (`canWriteHostContent` in\n * the rules, the same three roles at the routes). Those are now keys whose\n * preset is that site role (`presetFromSiteRole`), so every member keeps\n * exactly the access they had, and a custom role, a member's own permissions\n * or a site's toggle can grant or refuse either one: the window's staff can\n * be allowed walk-ins without editing anyone's booking.\n */\n\n/** The reservation keys. */\nexport type ReservationPermission = 'commerce.reservations' | 'commerce.walkIns'\n\n/** Commerce's keys whose preset is the site role (AGL-4047). */\nexport type CommerceSitePermission =\n | ReservationPermission\n | 'commerce.orders'\n | 'commerce.giftCards'\n | 'commerce.paymentMethods'\n | 'commerce.shippingConnections'\n\n/** Who held reservations on a site before they were keys: Admin, Editor and Author. */\nexport const RESERVATION_SITE_ROLE_PRESET: Readonly<Record<HostAccessRole, boolean>> = {\n admin: true,\n editor: true,\n author: true,\n viewer: false,\n}\n\n/** The same, per workspace role: the answer with no site named. */\nconst RESERVATION_ORG_ROLE_PRESET = { owner: true, admin: true, editor: true, viewer: false } as const\n\n/**\n * Who worked a site's orders and gift cards before they were keys: the site's\n * Admin and Editor (an Author edits the catalog and never touched an order).\n */\nexport const ORDERS_SITE_ROLE_PRESET: Readonly<Record<HostAccessRole, boolean>> = {\n admin: true,\n editor: true,\n author: false,\n viewer: false,\n}\n\n/**\n * Who changed a site's payment methods and its shipping app connections\n * before they were keys: the site's Admin alone (an Editor could see them, as\n * whoever works the orders still can).\n */\nexport const STORE_SETTINGS_SITE_ROLE_PRESET: Readonly<Record<HostAccessRole, boolean>> = {\n admin: true,\n editor: false,\n author: false,\n viewer: false,\n}\n\n/** The same, per workspace role: the answer with no site named. */\nconst STORE_SETTINGS_ORG_ROLE_PRESET = { owner: true, admin: true, editor: false, viewer: false } as const\n\n/**\n * The reservation keys as commerce declares them into the org permission\n * catalog (AGL-4047), registered beside `COMMERCE_PERMISSIONS`.\n */\nexport const COMMERCE_SITE_PERMISSIONS: readonly PluginOrgPermissionDeclaration[] = [\n {\n key: 'commerce.reservations',\n label: 'Manage reservations',\n description:\n 'Edit, cancel and check out stays, and add, change and remove what can be booked. Follows the site role unless a role or member sets it.',\n roleDefaults: { ...RESERVATION_ORG_ROLE_PRESET },\n hostRoleDefaults: { ...RESERVATION_SITE_ROLE_PRESET },\n group: 'commerce',\n groupLabel: 'Commerce',\n presetFromSiteRole: true,\n },\n {\n key: 'commerce.walkIns',\n label: 'Book walk-ins and change guests',\n description:\n 'Book a walk-in stay and change how many guests a stay is for. Follows \"Manage reservations\" unless a role or member sets it, and may be allowed without it.',\n roleDefaults: { ...RESERVATION_ORG_ROLE_PRESET },\n hostRoleDefaults: { ...RESERVATION_SITE_ROLE_PRESET },\n group: 'commerce',\n groupLabel: 'Commerce',\n presetFromSiteRole: true,\n follows: 'commerce.reservations',\n },\n {\n key: 'commerce.orders',\n label: 'Manage orders',\n description:\n 'Fulfill, cancel and print orders, resend receipts, build draft orders, take returns and record shipments. Follows the site role unless a role or member sets it.',\n roleDefaults: { ...RESERVATION_ORG_ROLE_PRESET },\n hostRoleDefaults: { ...ORDERS_SITE_ROLE_PRESET },\n group: 'commerce',\n groupLabel: 'Commerce',\n presetFromSiteRole: true,\n },\n {\n key: 'commerce.giftCards',\n label: 'Issue gift cards',\n description: 'Issue, adjust and void the store’s gift cards. Follows the site role unless a role or member sets it.',\n roleDefaults: { ...RESERVATION_ORG_ROLE_PRESET },\n hostRoleDefaults: { ...ORDERS_SITE_ROLE_PRESET },\n group: 'commerce',\n groupLabel: 'Commerce',\n presetFromSiteRole: true,\n },\n {\n key: 'commerce.paymentMethods',\n label: 'Manage payment methods',\n description:\n 'Turn the store’s payment methods on and off. Anyone with \"Manage orders\" sees them. Follows the site role unless a role or member sets it.',\n roleDefaults: { ...STORE_SETTINGS_ORG_ROLE_PRESET },\n hostRoleDefaults: { ...STORE_SETTINGS_SITE_ROLE_PRESET },\n group: 'commerce',\n groupLabel: 'Commerce',\n presetFromSiteRole: true,\n },\n {\n key: 'commerce.shippingConnections',\n label: 'Connect shipping apps',\n description:\n 'Connect, sync and disconnect ShipStation and ShippingEasy, and show or replace their credentials. Anyone with \"Manage orders\" sees whether they are connected. Follows the site role unless a role or member sets it.',\n roleDefaults: { ...STORE_SETTINGS_ORG_ROLE_PRESET },\n hostRoleDefaults: { ...STORE_SETTINGS_SITE_ROLE_PRESET },\n group: 'commerce',\n groupLabel: 'Commerce',\n presetFromSiteRole: true,\n },\n]\n\n/** The refusal a door answers when a commerce site key is not held: names the permission. */\nexport function commerceSitePermissionRefusal(key: CommerceSitePermission): string {\n const label = COMMERCE_SITE_PERMISSIONS.find((entry) => entry.key === key)?.label ?? key\n return `Your role does not include \"${label}\" — ask an organization admin`\n}\n\n/** One reservation key's label, for a refusal. */\nexport function reservationPermissionLabel(permission: ReservationPermission): string {\n return COMMERCE_SITE_PERMISSIONS.find((entry) => entry.key === permission)?.label ?? permission\n}\n\n/** The refusal a reservation route answers when its key is not held; names the permission, never a role. */\nexport function reservationPermissionRefusal(permission: ReservationPermission): string {\n return commerceSitePermissionRefusal(permission)\n}\n"],"names":["POS_TIER_DEFAULTS","admin","editor","viewer","COMMERCE_PERMISSIONS","key","pluginId","label","description","defaults","groupLabel","narrowsPerSite","refines","follows","posPermissionLabel","permission","find","entry","holdsPosPermission","permissions","own","mayVisitPosHardwareShop","posPermissionRefusal","RESERVATION_SITE_ROLE_PRESET","author","RESERVATION_ORG_ROLE_PRESET","owner","ORDERS_SITE_ROLE_PRESET","STORE_SETTINGS_SITE_ROLE_PRESET","STORE_SETTINGS_ORG_ROLE_PRESET","COMMERCE_SITE_PERMISSIONS","roleDefaults","hostRoleDefaults","group","presetFromSiteRole","commerceSitePermissionRefusal","reservationPermissionLabel","reservationPermissionRefusal"],"mappings":"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"}
1
+ {"version":3,"sources":["../../../../../../../libs/plugins/commerce/src/lib/model/plugin-permissions.ts"],"sourcesContent":["/**\n * @license\n * Copyright 2026 Aglyn LLC\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport type { HostAccessRole } from '@aglyn/aglyn/foundation/definitions/organization.types'\nimport type { PluginOrgPermissionDeclaration } from '@aglyn/aglyn/plugin-manager/plugin-entitlements'\nimport type { PluginPermission } from '@aglyn/aglyn/plugin-manager/plugin-permissions'\n\n/**\n * The register's finer permissions (AGL-4047), each a part of `managePos`\n * (Use the point of sale). Each REFINES it: never held without it, and,\n * where no custom role or override sets one, it follows `managePos` — so a\n * member keeps exactly the register they had until somebody narrows it.\n */\nexport type PosRegisterPermission =\n | 'posSell'\n | 'posRefund'\n | 'posDiscount'\n | 'posCashDrawer'\n | 'posDevices'\n\n/**\n * The register's keys and `posBuyHardware`, which stands on its own\n * (AGL-4047): it FOLLOWS `managePos` where no custom role or override sets\n * it, so every member keeps the hardware shop they had, but it may be\n * granted without the register — a bookkeeper who orders the store's readers\n * and never rings a sale.\n */\nexport type PosPermission = PosRegisterPermission | 'posBuyHardware'\n\n/** The tier defaults `managePos` has, which every finer key mirrors. */\nconst POS_TIER_DEFAULTS = { admin: true, editor: true, viewer: false } as const\n\n/*\n * The register is a site's own (AGL-4047): `managePos` and its five finer\n * keys are `narrowsPerSite`, so an editor of the whole workspace given Viewer\n * or Author access to one site does not work that site's register unless the\n * site grants it to them. `posBuyHardware` is not: the hardware shop spends\n * the workspace's money, and its verdict is the workspace's on every site.\n */\n\n/**\n * Commerce's plugin-declared permissions (AGL-435) — the reference\n * adopter. Pure data: the client barrel and /server entry both register\n * it, so console gating and API-side resolution agree.\n */\nexport const COMMERCE_PERMISSIONS: readonly PluginPermission[] = [\n {\n key: 'managePos',\n pluginId: 'commerce',\n label: 'Use the point of sale',\n description:\n 'Open the point of sale. Each point of sale permission below follows this one unless a role or member sets it.',\n defaults: { ...POS_TIER_DEFAULTS },\n groupLabel: 'Commerce',\n narrowsPerSite: true,\n },\n {\n key: 'posSell',\n pluginId: 'commerce',\n label: 'Sell at the register',\n description: 'Ring up sales and take payment at the register, the kiosk and the point of sale apps.',\n defaults: { ...POS_TIER_DEFAULTS },\n groupLabel: 'Commerce',\n narrowsPerSite: true,\n refines: 'managePos',\n },\n {\n key: 'posRefund',\n pluginId: 'commerce',\n label: 'Refunds and returns',\n description: 'Refund point of sale orders at the register, up to its refund limit, and take returns and exchanges.',\n defaults: { ...POS_TIER_DEFAULTS },\n groupLabel: 'Commerce',\n narrowsPerSite: true,\n refines: 'managePos',\n },\n {\n key: 'posDiscount',\n pluginId: 'commerce',\n label: 'Give discounts at the register',\n description:\n 'Take a discount off a sale at the register. A shopper’s discount code and the store’s own promotions apply without it.',\n defaults: { ...POS_TIER_DEFAULTS },\n groupLabel: 'Commerce',\n narrowsPerSite: true,\n refines: 'managePos',\n },\n {\n key: 'posCashDrawer',\n pluginId: 'commerce',\n label: 'Cash drawer and shifts',\n description: 'Open and close shifts, record cash in and out, print shift reports and open the drawer without a sale.',\n defaults: { ...POS_TIER_DEFAULTS },\n groupLabel: 'Commerce',\n narrowsPerSite: true,\n refines: 'managePos',\n },\n {\n key: 'posDevices',\n pluginId: 'commerce',\n label: 'Registers and devices',\n description: 'Add, change and remove card readers, receipt printers and customer displays, and set the reader screen.',\n defaults: { ...POS_TIER_DEFAULTS },\n groupLabel: 'Commerce',\n narrowsPerSite: true,\n refines: 'managePos',\n },\n {\n key: 'posBuyHardware',\n pluginId: 'commerce',\n label: 'Buy point of sale hardware',\n description:\n 'Order card readers and other hardware from the hardware shop. Follows \"Use the point of sale\" unless a role or member sets it, and may be allowed without it.',\n defaults: { ...POS_TIER_DEFAULTS },\n groupLabel: 'Commerce',\n follows: 'managePos',\n },\n]\n\n/** One finer register key's label, for a refusal or a disabled control's reason. */\nexport function posPermissionLabel(permission: PosPermission): string {\n return COMMERCE_PERMISSIONS.find((entry) => entry.key === permission)?.label ?? permission\n}\n\n/**\n * Whether a resolved permission map allows one of the register's finer\n * actions (AGL-4047): `managePos`, and the finer key not refused. A map\n * that does not carry the finer key at all follows `managePos` — the\n * resolvers always carry it once commerce has registered, so an absent key\n * is a map built before that, which keeps the register it had.\n *\n * `posBuyHardware` stands on its own: its own verdict when the map carries\n * one, granted with or without `managePos`, and `managePos`'s when it does\n * not.\n */\nexport function holdsPosPermission(\n permissions: Readonly<Record<string, boolean | undefined>> | null | undefined,\n permission: PosPermission,\n): boolean {\n if (permission === 'posBuyHardware') {\n const own = permissions?.[permission]\n return typeof own === 'boolean' ? own : permissions?.['managePos'] === true\n }\n return permissions?.['managePos'] === true && permissions?.[permission] !== false\n}\n\n/**\n * Whether a member may open the hardware shop at all (AGL-4047): see what\n * it offers and what the store ordered. Whoever works the register, and\n * whoever may buy hardware without working it.\n */\nexport function mayVisitPosHardwareShop(\n permissions: Readonly<Record<string, boolean | undefined>> | null | undefined,\n): boolean {\n return permissions?.['managePos'] === true || holdsPosPermission(permissions, 'posBuyHardware')\n}\n\n/** The refusal a register route answers when a finer key is not held. */\nexport function posPermissionRefusal(permission: PosPermission): string {\n return `Your role does not include \"${posPermissionLabel(permission)}\" — ask an organization admin`\n}\n\n/*\n * RESERVATIONS (AGL-4047).\n *\n * A site's stays and what they book were decided by the member's role ON THE\n * SITE: Admin, Editor and Author could book a walk-in, change a stay's guests\n * and edit or cancel stays, and a Viewer could not (`canWriteHostContent` in\n * the rules, the same three roles at the routes). Those are now keys whose\n * preset is that site role (`presetFromSiteRole`), so every member keeps\n * exactly the access they had, and a custom role, a member's own permissions\n * or a site's toggle can grant or refuse either one: the window's staff can\n * be allowed walk-ins without editing anyone's booking.\n */\n\n/** The reservation keys. */\nexport type ReservationPermission = 'commerce.reservations' | 'commerce.walkIns'\n\n/** Commerce's keys whose preset is the site role (AGL-4047). */\nexport type CommerceSitePermission =\n | ReservationPermission\n | 'commerce.orders'\n | 'commerce.giftCards'\n | 'commerce.paymentMethods'\n | 'commerce.shippingConnections'\n\n/** Who held reservations on a site before they were keys: Admin, Editor and Author. */\nexport const RESERVATION_SITE_ROLE_PRESET: Readonly<Record<HostAccessRole, boolean>> = {\n admin: true,\n editor: true,\n author: true,\n viewer: false,\n}\n\n/** The same, per workspace role: the answer with no site named. */\nconst RESERVATION_ORG_ROLE_PRESET = { owner: true, admin: true, editor: true, viewer: false } as const\n\n/**\n * Who worked a site's orders and gift cards before they were keys: the site's\n * Admin and Editor (an Author edits the catalog and never touched an order).\n */\nexport const ORDERS_SITE_ROLE_PRESET: Readonly<Record<HostAccessRole, boolean>> = {\n admin: true,\n editor: true,\n author: false,\n viewer: false,\n}\n\n/**\n * Who changed a site's payment methods and its shipping app connections\n * before they were keys: the site's Admin alone (an Editor could see them, as\n * whoever works the orders still can).\n */\nexport const STORE_SETTINGS_SITE_ROLE_PRESET: Readonly<Record<HostAccessRole, boolean>> = {\n admin: true,\n editor: false,\n author: false,\n viewer: false,\n}\n\n/** The same, per workspace role: the answer with no site named. */\nexport const STORE_SETTINGS_ORG_ROLE_PRESET = { owner: true, admin: true, editor: false, viewer: false } as const\n\n/**\n * The reservation keys as commerce declares them into the org permission\n * catalog (AGL-4047), registered beside `COMMERCE_PERMISSIONS`.\n */\nexport const COMMERCE_SITE_PERMISSIONS: readonly PluginOrgPermissionDeclaration[] = [\n {\n key: 'commerce.reservations',\n label: 'Manage reservations',\n description:\n 'Edit, cancel and check out stays, and add, change and remove what can be booked. Follows the site role unless a role or member sets it.',\n roleDefaults: { ...RESERVATION_ORG_ROLE_PRESET },\n hostRoleDefaults: { ...RESERVATION_SITE_ROLE_PRESET },\n group: 'commerce',\n groupLabel: 'Commerce',\n presetFromSiteRole: true,\n },\n {\n key: 'commerce.walkIns',\n label: 'Book walk-ins and change guests',\n description:\n 'Book a walk-in stay and change how many guests a stay is for. Follows \"Manage reservations\" unless a role or member sets it, and may be allowed without it.',\n roleDefaults: { ...RESERVATION_ORG_ROLE_PRESET },\n hostRoleDefaults: { ...RESERVATION_SITE_ROLE_PRESET },\n group: 'commerce',\n groupLabel: 'Commerce',\n presetFromSiteRole: true,\n follows: 'commerce.reservations',\n },\n {\n key: 'commerce.orders',\n label: 'Manage orders',\n description:\n 'Fulfill, cancel and print orders, resend receipts, build draft orders, take returns and record shipments. Follows the site role unless a role or member sets it.',\n roleDefaults: { ...RESERVATION_ORG_ROLE_PRESET },\n hostRoleDefaults: { ...ORDERS_SITE_ROLE_PRESET },\n group: 'commerce',\n groupLabel: 'Commerce',\n presetFromSiteRole: true,\n },\n {\n key: 'commerce.giftCards',\n label: 'Issue gift cards',\n description: 'Issue, adjust and void the store’s gift cards. Follows the site role unless a role or member sets it.',\n roleDefaults: { ...RESERVATION_ORG_ROLE_PRESET },\n hostRoleDefaults: { ...ORDERS_SITE_ROLE_PRESET },\n group: 'commerce',\n groupLabel: 'Commerce',\n presetFromSiteRole: true,\n },\n {\n key: 'commerce.paymentMethods',\n label: 'Manage payment methods',\n description:\n 'Turn the store’s payment methods on and off. Anyone with \"Manage orders\" sees them. Follows the site role unless a role or member sets it.',\n roleDefaults: { ...STORE_SETTINGS_ORG_ROLE_PRESET },\n hostRoleDefaults: { ...STORE_SETTINGS_SITE_ROLE_PRESET },\n group: 'commerce',\n groupLabel: 'Commerce',\n presetFromSiteRole: true,\n },\n {\n key: 'commerce.shippingConnections',\n label: 'Connect shipping apps',\n description:\n 'Connect, sync and disconnect ShipStation and ShippingEasy, and show or replace their credentials. Anyone with \"Manage orders\" sees whether they are connected. Follows the site role unless a role or member sets it.',\n roleDefaults: { ...STORE_SETTINGS_ORG_ROLE_PRESET },\n hostRoleDefaults: { ...STORE_SETTINGS_SITE_ROLE_PRESET },\n group: 'commerce',\n groupLabel: 'Commerce',\n presetFromSiteRole: true,\n },\n]\n\n/** The refusal a door answers when a commerce site key is not held: names the permission. */\nexport function commerceSitePermissionRefusal(key: CommerceSitePermission): string {\n const label = COMMERCE_SITE_PERMISSIONS.find((entry) => entry.key === key)?.label ?? key\n return `Your role does not include \"${label}\" — ask an organization admin`\n}\n\n/** One reservation key's label, for a refusal. */\nexport function reservationPermissionLabel(permission: ReservationPermission): string {\n return COMMERCE_SITE_PERMISSIONS.find((entry) => entry.key === permission)?.label ?? permission\n}\n\n/** The refusal a reservation route answers when its key is not held; names the permission, never a role. */\nexport function reservationPermissionRefusal(permission: ReservationPermission): string {\n return commerceSitePermissionRefusal(permission)\n}\n"],"names":["POS_TIER_DEFAULTS","admin","editor","viewer","COMMERCE_PERMISSIONS","key","pluginId","label","description","defaults","groupLabel","narrowsPerSite","refines","follows","posPermissionLabel","permission","find","entry","holdsPosPermission","permissions","own","mayVisitPosHardwareShop","posPermissionRefusal","RESERVATION_SITE_ROLE_PRESET","author","RESERVATION_ORG_ROLE_PRESET","owner","ORDERS_SITE_ROLE_PRESET","STORE_SETTINGS_SITE_ROLE_PRESET","STORE_SETTINGS_ORG_ROLE_PRESET","COMMERCE_SITE_PERMISSIONS","roleDefaults","hostRoleDefaults","group","presetFromSiteRole","commerceSitePermissionRefusal","reservationPermissionLabel","reservationPermissionRefusal"],"mappings":"AAAA;;;;;;;;;;;;;;;CAeC;AA4BD,sEAAsE,GACtE,MAAMA,oBAAoB;IAAEC,OAAO;IAAMC,QAAQ;IAAMC,QAAQ;AAAM;AAErE;;;;;;CAMC,GAED;;;;CAIC,GACD,OAAO,MAAMC,uBAAoD;IAC/D;QACEC,KAAK;QACLC,UAAU;QACVC,OAAO;QACPC,aACE;QACFC,UAAU,aAAKT;QACfU,YAAY;QACZC,gBAAgB;IAClB;IACA;QACEN,KAAK;QACLC,UAAU;QACVC,OAAO;QACPC,aAAa;QACbC,UAAU,aAAKT;QACfU,YAAY;QACZC,gBAAgB;QAChBC,SAAS;IACX;IACA;QACEP,KAAK;QACLC,UAAU;QACVC,OAAO;QACPC,aAAa;QACbC,UAAU,aAAKT;QACfU,YAAY;QACZC,gBAAgB;QAChBC,SAAS;IACX;IACA;QACEP,KAAK;QACLC,UAAU;QACVC,OAAO;QACPC,aACE;QACFC,UAAU,aAAKT;QACfU,YAAY;QACZC,gBAAgB;QAChBC,SAAS;IACX;IACA;QACEP,KAAK;QACLC,UAAU;QACVC,OAAO;QACPC,aAAa;QACbC,UAAU,aAAKT;QACfU,YAAY;QACZC,gBAAgB;QAChBC,SAAS;IACX;IACA;QACEP,KAAK;QACLC,UAAU;QACVC,OAAO;QACPC,aAAa;QACbC,UAAU,aAAKT;QACfU,YAAY;QACZC,gBAAgB;QAChBC,SAAS;IACX;IACA;QACEP,KAAK;QACLC,UAAU;QACVC,OAAO;QACPC,aACE;QACFC,UAAU,aAAKT;QACfU,YAAY;QACZG,SAAS;IACX;CACD,CAAA;AAED,kFAAkF,GAClF,OAAO,SAASC,mBAAmBC,UAAyB;;QACnDX;IAAP,gBAAOA,6BAAAA,qBAAqBY,IAAI,CAAC,CAACC,QAAUA,MAAMZ,GAAG,KAAKU,gCAAnDX,2BAAgEG,KAAK,mBAAIQ;AAClF;AAEA;;;;;;;;;;CAUC,GACD,OAAO,SAASG,mBACdC,WAA6E,EAC7EJ,UAAyB;IAEzB,IAAIA,eAAe,kBAAkB;QACnC,MAAMK,MAAMD,+BAAAA,WAAa,CAACJ,WAAW;QACrC,OAAO,OAAOK,QAAQ,YAAYA,MAAMD,CAAAA,+BAAAA,WAAa,CAAC,YAAY,MAAK;IACzE;IACA,OAAOA,CAAAA,+BAAAA,WAAa,CAAC,YAAY,MAAK,QAAQA,CAAAA,+BAAAA,WAAa,CAACJ,WAAW,MAAK;AAC9E;AAEA;;;;CAIC,GACD,OAAO,SAASM,wBACdF,WAA6E;IAE7E,OAAOA,CAAAA,+BAAAA,WAAa,CAAC,YAAY,MAAK,QAAQD,mBAAmBC,aAAa;AAChF;AAEA,uEAAuE,GACvE,OAAO,SAASG,qBAAqBP,UAAyB;IAC5D,OAAO,CAAC,4BAA4B,EAAED,mBAAmBC,YAAY,6BAA6B,CAAC;AACrG;AA0BA,qFAAqF,GACrF,OAAO,MAAMQ,+BAA0E;IACrFtB,OAAO;IACPC,QAAQ;IACRsB,QAAQ;IACRrB,QAAQ;AACV,EAAC;AAED,iEAAiE,GACjE,MAAMsB,8BAA8B;IAAEC,OAAO;IAAMzB,OAAO;IAAMC,QAAQ;IAAMC,QAAQ;AAAM;AAE5F;;;CAGC,GACD,OAAO,MAAMwB,0BAAqE;IAChF1B,OAAO;IACPC,QAAQ;IACRsB,QAAQ;IACRrB,QAAQ;AACV,EAAC;AAED;;;;CAIC,GACD,OAAO,MAAMyB,kCAA6E;IACxF3B,OAAO;IACPC,QAAQ;IACRsB,QAAQ;IACRrB,QAAQ;AACV,EAAC;AAED,iEAAiE,GACjE,OAAO,MAAM0B,iCAAiC;IAAEH,OAAO;IAAMzB,OAAO;IAAMC,QAAQ;IAAOC,QAAQ;AAAM,EAAU;AAEjH;;;CAGC,GACD,OAAO,MAAM2B,4BAAuE;IAClF;QACEzB,KAAK;QACLE,OAAO;QACPC,aACE;QACFuB,cAAc,aAAKN;QACnBO,kBAAkB,aAAKT;QACvBU,OAAO;QACPvB,YAAY;QACZwB,oBAAoB;IACtB;IACA;QACE7B,KAAK;QACLE,OAAO;QACPC,aACE;QACFuB,cAAc,aAAKN;QACnBO,kBAAkB,aAAKT;QACvBU,OAAO;QACPvB,YAAY;QACZwB,oBAAoB;QACpBrB,SAAS;IACX;IACA;QACER,KAAK;QACLE,OAAO;QACPC,aACE;QACFuB,cAAc,aAAKN;QACnBO,kBAAkB,aAAKL;QACvBM,OAAO;QACPvB,YAAY;QACZwB,oBAAoB;IACtB;IACA;QACE7B,KAAK;QACLE,OAAO;QACPC,aAAa;QACbuB,cAAc,aAAKN;QACnBO,kBAAkB,aAAKL;QACvBM,OAAO;QACPvB,YAAY;QACZwB,oBAAoB;IACtB;IACA;QACE7B,KAAK;QACLE,OAAO;QACPC,aACE;QACFuB,cAAc,aAAKF;QACnBG,kBAAkB,aAAKJ;QACvBK,OAAO;QACPvB,YAAY;QACZwB,oBAAoB;IACtB;IACA;QACE7B,KAAK;QACLE,OAAO;QACPC,aACE;QACFuB,cAAc,aAAKF;QACnBG,kBAAkB,aAAKJ;QACvBK,OAAO;QACPvB,YAAY;QACZwB,oBAAoB;IACtB;CACD,CAAA;AAED,2FAA2F,GAC3F,OAAO,SAASC,8BAA8B9B,GAA2B;;QACzDyB;IAAd,MAAMvB,iBAAQuB,kCAAAA,0BAA0Bd,IAAI,CAAC,CAACC,QAAUA,MAAMZ,GAAG,KAAKA,yBAAxDyB,gCAA8DvB,KAAK,mBAAIF;IACrF,OAAO,CAAC,4BAA4B,EAAEE,MAAM,6BAA6B,CAAC;AAC5E;AAEA,gDAAgD,GAChD,OAAO,SAAS6B,2BAA2BrB,UAAiC;;QACnEe;IAAP,gBAAOA,kCAAAA,0BAA0Bd,IAAI,CAAC,CAACC,QAAUA,MAAMZ,GAAG,KAAKU,gCAAxDe,gCAAqEvB,KAAK,mBAAIQ;AACvF;AAEA,0GAA0G,GAC1G,OAAO,SAASsB,6BAA6BtB,UAAiC;IAC5E,OAAOoB,8BAA8BpB;AACvC"}
@@ -0,0 +1,26 @@
1
+ /**
2
+ * @license
3
+ * Copyright 2026 Aglyn LLC
4
+ *
5
+ * Licensed under the Apache License, Version 2.0 (the "License");
6
+ * you may not use this file except in compliance with the License.
7
+ * You may obtain a copy of the License at
8
+ *
9
+ * http://www.apache.org/licenses/LICENSE-2.0
10
+ *
11
+ * Unless required by applicable law or agreed to in writing, software
12
+ * distributed under the License is distributed on an "AS IS" BASIS,
13
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14
+ * See the License for the specific language governing permissions and
15
+ * limitations under the License.
16
+ */
17
+ import type { HostAccessRole } from '@aglyn/aglyn/foundation/definitions/organization.types';
18
+ import type { PluginOrgPermissionDeclaration } from '@aglyn/aglyn/plugin-manager/plugin-entitlements';
19
+ /** Commerce's keys whose site-role preset holds for members of the whole workspace only. */
20
+ export type CommerceWorkspaceSitePermission = 'commerce.refunds' | 'commerce.posApprovals' | 'commerce.webhooks';
21
+ /** The site Admin, read for members of the whole workspace only. */
22
+ export declare const WORKSPACE_ADMIN_SITE_ROLE_PRESET: Readonly<Record<HostAccessRole, boolean>>;
23
+ /** The keys as commerce declares them, after `COMMERCE_SITE_PERMISSIONS`. */
24
+ export declare const COMMERCE_WORKSPACE_SITE_PERMISSIONS: readonly PluginOrgPermissionDeclaration[];
25
+ /** The refusal a door answers when one of these keys is not held: names the permission, never a role. */
26
+ export declare function commerceWorkspacePermissionRefusal(key: CommerceWorkspaceSitePermission): string;
@@ -0,0 +1,81 @@
1
+ /**
2
+ * @license
3
+ * Copyright 2026 Aglyn LLC
4
+ *
5
+ * Licensed under the Apache License, Version 2.0 (the "License");
6
+ * you may not use this file except in compliance with the License.
7
+ * You may obtain a copy of the License at
8
+ *
9
+ * http://www.apache.org/licenses/LICENSE-2.0
10
+ *
11
+ * Unless required by applicable law or agreed to in writing, software
12
+ * distributed under the License is distributed on an "AS IS" BASIS,
13
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14
+ * See the License for the specific language governing permissions and
15
+ * limitations under the License.
16
+ */ import { _ as _extends } from "@swc/helpers/_/_extends";
17
+ /** The site Admin, read for members of the whole workspace only. */ export const WORKSPACE_ADMIN_SITE_ROLE_PRESET = {
18
+ admin: true,
19
+ editor: false,
20
+ author: false,
21
+ viewer: false
22
+ };
23
+ /** Who holds each before anyone sets it, as its description ends. */ const HOLDS = 'A member of the whole workspace who is the site’s admin holds it unless a role or member sets it; someone added to just this site holds it only when the site grants it.';
24
+ /** The keys as commerce declares them, after `COMMERCE_SITE_PERMISSIONS`. */ export const COMMERCE_WORKSPACE_SITE_PERMISSIONS = [
25
+ {
26
+ key: 'commerce.refunds',
27
+ label: 'Refund orders',
28
+ description: `Refund any order, online or at the register, in full or in part, with no register limit. ${HOLDS}`,
29
+ roleDefaults: {
30
+ owner: true,
31
+ admin: true,
32
+ editor: false,
33
+ viewer: false
34
+ },
35
+ hostRoleDefaults: _extends({}, WORKSPACE_ADMIN_SITE_ROLE_PRESET),
36
+ group: 'commerce',
37
+ groupLabel: 'Commerce',
38
+ presetFromSiteRole: true,
39
+ workspaceMembersOnly: true
40
+ },
41
+ {
42
+ key: 'commerce.posApprovals',
43
+ label: 'Approve refunds over the register’s limit',
44
+ description: `Refund at the register above its refund limit, approve a cashier’s refund over it with a PIN, and set or clear other staff members’ PINs. ${HOLDS}`,
45
+ roleDefaults: {
46
+ owner: true,
47
+ admin: true,
48
+ editor: false,
49
+ viewer: false
50
+ },
51
+ hostRoleDefaults: _extends({}, WORKSPACE_ADMIN_SITE_ROLE_PRESET),
52
+ group: 'commerce',
53
+ groupLabel: 'Commerce',
54
+ presetFromSiteRole: true,
55
+ workspaceMembersOnly: true
56
+ },
57
+ {
58
+ key: 'commerce.webhooks',
59
+ label: 'Manage order webhooks',
60
+ description: `Add, change, test and remove the store’s order webhooks, roll their secrets and resend deliveries. ${HOLDS}`,
61
+ roleDefaults: {
62
+ owner: true,
63
+ admin: true,
64
+ editor: false,
65
+ viewer: false
66
+ },
67
+ hostRoleDefaults: _extends({}, WORKSPACE_ADMIN_SITE_ROLE_PRESET),
68
+ group: 'commerce',
69
+ groupLabel: 'Commerce',
70
+ presetFromSiteRole: true,
71
+ workspaceMembersOnly: true
72
+ }
73
+ ];
74
+ /** The refusal a door answers when one of these keys is not held: names the permission, never a role. */ export function commerceWorkspacePermissionRefusal(key) {
75
+ var _ref;
76
+ var _COMMERCE_WORKSPACE_SITE_PERMISSIONS_find;
77
+ const label = (_ref = (_COMMERCE_WORKSPACE_SITE_PERMISSIONS_find = COMMERCE_WORKSPACE_SITE_PERMISSIONS.find((entry)=>entry.key === key)) == null ? void 0 : _COMMERCE_WORKSPACE_SITE_PERMISSIONS_find.label) != null ? _ref : key;
78
+ return `Your role does not include "${label}" — ask an organization admin`;
79
+ }
80
+
81
+ //# sourceMappingURL=workspace-site-permissions.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../../../../../../libs/plugins/commerce/src/lib/model/workspace-site-permissions.ts"],"sourcesContent":["/**\n * @license\n * Copyright 2026 Aglyn LLC\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport type { HostAccessRole } from '@aglyn/aglyn/foundation/definitions/organization.types'\nimport type { PluginOrgPermissionDeclaration } from '@aglyn/aglyn/plugin-manager/plugin-entitlements'\n\n/*\n * REFUNDS, THE REGISTER'S APPROVALS AND ORDER WEBHOOKS (AGL-4047).\n *\n * Refunding an order, approving a refund over the register's limit (and\n * setting other staff members' PINs), and managing order webhooks asked for\n * an admin of the WHOLE workspace who is also the site's admin (`refund.ts`,\n * AGL-2372): a site's Members card can make a contractor the admin of one\n * site, which writes the same `'admin'` into `memberRoles` as an owner's, and\n * none of these were ever theirs. They are now keys whose preset is the site\n * role for members of the whole workspace only (`workspaceMembersOnly`): the\n * site's Admin among them, and nobody added to just that site unless the\n * site grants it. A custom role, a member's own permissions or the site's\n * toggle grants or refuses each one.\n *\n * Their own module, not `plugin-permissions.ts`: the storefront imports that\n * one, and only the declarations and the server doors read these.\n */\n\n/** Commerce's keys whose site-role preset holds for members of the whole workspace only. */\nexport type CommerceWorkspaceSitePermission = 'commerce.refunds' | 'commerce.posApprovals' | 'commerce.webhooks'\n\n/** The site Admin, read for members of the whole workspace only. */\nexport const WORKSPACE_ADMIN_SITE_ROLE_PRESET: Readonly<Record<HostAccessRole, boolean>> = {\n admin: true,\n editor: false,\n author: false,\n viewer: false,\n}\n\n/** Who holds each before anyone sets it, as its description ends. */\nconst HOLDS =\n 'A member of the whole workspace who is the site’s admin holds it unless a role or member sets it; someone added to just this site holds it only when the site grants it.'\n\n/** The keys as commerce declares them, after `COMMERCE_SITE_PERMISSIONS`. */\nexport const COMMERCE_WORKSPACE_SITE_PERMISSIONS: readonly PluginOrgPermissionDeclaration[] = [\n {\n key: 'commerce.refunds',\n label: 'Refund orders',\n description: `Refund any order, online or at the register, in full or in part, with no register limit. ${HOLDS}`,\n roleDefaults: { owner: true, admin: true, editor: false, viewer: false },\n hostRoleDefaults: { ...WORKSPACE_ADMIN_SITE_ROLE_PRESET },\n group: 'commerce',\n groupLabel: 'Commerce',\n presetFromSiteRole: true,\n workspaceMembersOnly: true,\n },\n {\n key: 'commerce.posApprovals',\n label: 'Approve refunds over the register’s limit',\n description: `Refund at the register above its refund limit, approve a cashier’s refund over it with a PIN, and set or clear other staff members’ PINs. ${HOLDS}`,\n roleDefaults: { owner: true, admin: true, editor: false, viewer: false },\n hostRoleDefaults: { ...WORKSPACE_ADMIN_SITE_ROLE_PRESET },\n group: 'commerce',\n groupLabel: 'Commerce',\n presetFromSiteRole: true,\n workspaceMembersOnly: true,\n },\n {\n key: 'commerce.webhooks',\n label: 'Manage order webhooks',\n description: `Add, change, test and remove the store’s order webhooks, roll their secrets and resend deliveries. ${HOLDS}`,\n roleDefaults: { owner: true, admin: true, editor: false, viewer: false },\n hostRoleDefaults: { ...WORKSPACE_ADMIN_SITE_ROLE_PRESET },\n group: 'commerce',\n groupLabel: 'Commerce',\n presetFromSiteRole: true,\n workspaceMembersOnly: true,\n },\n]\n\n/** The refusal a door answers when one of these keys is not held: names the permission, never a role. */\nexport function commerceWorkspacePermissionRefusal(key: CommerceWorkspaceSitePermission): string {\n const label = COMMERCE_WORKSPACE_SITE_PERMISSIONS.find((entry) => entry.key === key)?.label ?? key\n return `Your role does not include \"${label}\" — ask an organization admin`\n}\n"],"names":["WORKSPACE_ADMIN_SITE_ROLE_PRESET","admin","editor","author","viewer","HOLDS","COMMERCE_WORKSPACE_SITE_PERMISSIONS","key","label","description","roleDefaults","owner","hostRoleDefaults","group","groupLabel","presetFromSiteRole","workspaceMembersOnly","commerceWorkspacePermissionRefusal","find","entry"],"mappings":"AAAA;;;;;;;;;;;;;;;CAeC;AA0BD,kEAAkE,GAClE,OAAO,MAAMA,mCAA8E;IACzFC,OAAO;IACPC,QAAQ;IACRC,QAAQ;IACRC,QAAQ;AACV,EAAC;AAED,mEAAmE,GACnE,MAAMC,QACJ;AAEF,2EAA2E,GAC3E,OAAO,MAAMC,sCAAiF;IAC5F;QACEC,KAAK;QACLC,OAAO;QACPC,aAAa,CAAC,yFAAyF,EAAEJ,OAAO;QAChHK,cAAc;YAAEC,OAAO;YAAMV,OAAO;YAAMC,QAAQ;YAAOE,QAAQ;QAAM;QACvEQ,kBAAkB,aAAKZ;QACvBa,OAAO;QACPC,YAAY;QACZC,oBAAoB;QACpBC,sBAAsB;IACxB;IACA;QACET,KAAK;QACLC,OAAO;QACPC,aAAa,CAAC,0IAA0I,EAAEJ,OAAO;QACjKK,cAAc;YAAEC,OAAO;YAAMV,OAAO;YAAMC,QAAQ;YAAOE,QAAQ;QAAM;QACvEQ,kBAAkB,aAAKZ;QACvBa,OAAO;QACPC,YAAY;QACZC,oBAAoB;QACpBC,sBAAsB;IACxB;IACA;QACET,KAAK;QACLC,OAAO;QACPC,aAAa,CAAC,mGAAmG,EAAEJ,OAAO;QAC1HK,cAAc;YAAEC,OAAO;YAAMV,OAAO;YAAMC,QAAQ;YAAOE,QAAQ;QAAM;QACvEQ,kBAAkB,aAAKZ;QACvBa,OAAO;QACPC,YAAY;QACZC,oBAAoB;QACpBC,sBAAsB;IACxB;CACD,CAAA;AAED,uGAAuG,GACvG,OAAO,SAASC,mCAAmCV,GAAoC;;QACvED;IAAd,MAAME,iBAAQF,4CAAAA,oCAAoCY,IAAI,CAAC,CAACC,QAAUA,MAAMZ,GAAG,KAAKA,yBAAlED,0CAAwEE,KAAK,mBAAID;IAC/F,OAAO,CAAC,4BAA4B,EAAEC,MAAM,6BAA6B,CAAC;AAC5E"}
@@ -15,6 +15,7 @@
15
15
  * limitations under the License.
16
16
  */
17
17
  import { type CommerceSitePermission } from '../model/plugin-permissions';
18
+ import { type CommerceWorkspaceSitePermission } from '../model/workspace-site-permissions';
18
19
  /**
19
20
  * Does this member hold one of commerce's site keys on this site, as the
20
21
  * rules would read it (AGL-4047): the site's `memberPermissions` stamp, else
@@ -27,3 +28,21 @@ export declare function holdsCommerceSiteKey(host: {
27
28
  memberPermissions?: unknown;
28
29
  memberRoles?: unknown;
29
30
  } | null | undefined, uid: string, key: CommerceSitePermission): boolean;
31
+ /**
32
+ * Does this member hold one of commerce's keys whose preset holds for
33
+ * members of the whole workspace only (AGL-4047): refunds, the register's
34
+ * over-limit approvals, order webhooks. The site's stamp when the
35
+ * projection wrote one, else exactly the gate the key replaced: the site's
36
+ * Admin in `memberRoles`, a member of the whole workspace (`orgWide`), and
37
+ * Admin on the site as resolved now (`hostRole`). `membership` is the
38
+ * resolution every one of those doors reads already.
39
+ */
40
+ export declare function holdsCommerceWorkspaceSiteKey(hostDoc: {
41
+ get(field: string): unknown;
42
+ } | {
43
+ memberPermissions?: unknown;
44
+ memberRoles?: unknown;
45
+ } | null | undefined, uid: string, key: CommerceWorkspaceSitePermission, membership: {
46
+ orgWide: boolean;
47
+ hostRole: string | null | undefined;
48
+ }): boolean;
@@ -13,9 +13,13 @@
13
13
  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14
14
  * See the License for the specific language governing permissions and
15
15
  * limitations under the License.
16
- */ import { hostStampedSitePermission } from "@aglyn/aglyn/app-utils/host-permissions";
16
+ */ import { hostStampedSitePermission, hostStampedWorkspaceSitePermission } from "@aglyn/aglyn/app-utils/host-permissions";
17
17
  import { COMMERCE_SITE_PERMISSIONS } from "../model/plugin-permissions.js";
18
- /** Each commerce site key's site-role preset: the declarations' own table. */ const COMMERCE_SITE_PRESETS = Object.fromEntries(COMMERCE_SITE_PERMISSIONS.map((entry)=>{
18
+ import { COMMERCE_WORKSPACE_SITE_PERMISSIONS } from "../model/workspace-site-permissions.js";
19
+ /** Each commerce site key's site-role preset: the declarations' own table. */ const COMMERCE_SITE_PRESETS = Object.fromEntries([
20
+ ...COMMERCE_SITE_PERMISSIONS,
21
+ ...COMMERCE_WORKSPACE_SITE_PERMISSIONS
22
+ ].map((entry)=>{
19
23
  var _entry_hostRoleDefaults;
20
24
  return [
21
25
  entry.key,
@@ -36,5 +40,22 @@ import { COMMERCE_SITE_PERMISSIONS } from "../model/plugin-permissions.js";
36
40
  memberRoles: read('memberRoles')
37
41
  }, uid, key, (_COMMERCE_SITE_PRESETS_key = COMMERCE_SITE_PRESETS[key]) != null ? _COMMERCE_SITE_PRESETS_key : {});
38
42
  }
43
+ /**
44
+ * Does this member hold one of commerce's keys whose preset holds for
45
+ * members of the whole workspace only (AGL-4047): refunds, the register's
46
+ * over-limit approvals, order webhooks. The site's stamp when the
47
+ * projection wrote one, else exactly the gate the key replaced: the site's
48
+ * Admin in `memberRoles`, a member of the whole workspace (`orgWide`), and
49
+ * Admin on the site as resolved now (`hostRole`). `membership` is the
50
+ * resolution every one of those doors reads already.
51
+ */ export function holdsCommerceWorkspaceSiteKey(hostDoc, uid, key, membership) {
52
+ var _COMMERCE_SITE_PRESETS_key;
53
+ if (!hostDoc || !uid) return false;
54
+ const read = (field)=>typeof hostDoc.get === 'function' ? hostDoc.get(field) : hostDoc[field];
55
+ return hostStampedWorkspaceSitePermission({
56
+ memberPermissions: read('memberPermissions'),
57
+ memberRoles: read('memberRoles')
58
+ }, uid, key, (_COMMERCE_SITE_PRESETS_key = COMMERCE_SITE_PRESETS[key]) != null ? _COMMERCE_SITE_PRESETS_key : {}, membership);
59
+ }
39
60
 
40
61
  //# sourceMappingURL=commerce-site-keys.js.map