@aglyn/plugins-events-calendar 1.0.0-beta.204 → 1.0.0-beta.205

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-events-calendar",
3
- "version": "1.0.0-beta.204",
3
+ "version": "1.0.0-beta.205",
4
4
  "license": "Apache-2.0",
5
5
  "homepage": "https://aglyn.com",
6
6
  "repository": {
@@ -25,14 +25,14 @@
25
25
  "./package.json": "./package.json"
26
26
  },
27
27
  "dependencies": {
28
- "@aglyn/aglyn": "1.0.0-beta.204",
29
- "@aglyn/shared-data-mdi": "1.0.0-beta.204",
30
- "@aglyn/shared-ui-jsx": "1.0.0-beta.204",
31
- "@aglyn/shared-ui-snackstack": "1.0.0-beta.204",
32
- "@aglyn/shared-util-timestamp": "1.0.0-beta.204",
33
- "@aglyn/tenant-data-admin": "1.0.0-beta.204",
34
- "@aglyn/tenant-feature-instance": "1.0.0-beta.204",
35
- "@aglyn/tenant-runtime": "1.0.0-beta.204",
28
+ "@aglyn/aglyn": "1.0.0-beta.205",
29
+ "@aglyn/shared-data-mdi": "1.0.0-beta.205",
30
+ "@aglyn/shared-ui-jsx": "1.0.0-beta.205",
31
+ "@aglyn/shared-ui-snackstack": "1.0.0-beta.205",
32
+ "@aglyn/shared-util-timestamp": "1.0.0-beta.205",
33
+ "@aglyn/tenant-data-admin": "1.0.0-beta.205",
34
+ "@aglyn/tenant-feature-instance": "1.0.0-beta.205",
35
+ "@aglyn/tenant-runtime": "1.0.0-beta.205",
36
36
  "@swc/helpers": "0.5.23"
37
37
  },
38
38
  "peerDependencies": {
package/src/lib/server.js CHANGED
@@ -164,7 +164,12 @@ import { dispatchHostAutomation } from "@aglyn/tenant-runtime";
164
164
  }
165
165
  }
166
166
  }
167
- const alerts = await dispatchHostAutomation(hostId, actionId, event, payload);
167
+ // A visitor on the published page fired it (AGL-3376).
168
+ const alerts = await dispatchHostAutomation(hostId, actionId, event, payload, {
169
+ actor: {
170
+ kind: 'visitor'
171
+ }
172
+ });
168
173
  return res.status(200).json({
169
174
  ok: true,
170
175
  alerts
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../../../../libs/plugins/events-calendar/src/lib/server.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\n/**\n * Server half of the events-calendar plugin (AGL-396): the reference API\n * migration. Registers the public `events/list` handler with the plugin API\n * registry; the app dispatcher serves it at the unchanged `/api/events/list`\n * URL. This module imports firebase-admin, so it is NOT re-exported from the\n * plugin's client barrel — apps import `@aglyn/plugins-events-calendar/server`\n * only from their (server-only) API dispatcher.\n */\n\nimport {\n checkEntitlement,\n isSiteEventType,\n registerPluginApiRoute,\n resolveSocialImage,\n type PluginApiHandler,\n} from '@aglyn/aglyn/server'\nimport { firebaseAdmin, getOrgForHost } from '@aglyn/tenant-data-admin'\nimport { dispatchHostAutomation } from '@aglyn/tenant-runtime'\n\n/** How many events one listing returns. */\nconst EVENTS_LIST_LIMIT = 50\n\n/**\n * Public event listing (AGL-145): published events for the Event List canvas\n * element. Drafts never leave the server; the paid `eventCalendar` add-on\n * gates plan-holding workspaces (dark-launch workspaces pass). Sorted by start;\n * `mode=past` flips the window.\n */\nconst eventsListHandler: PluginApiHandler = async (req, res) => {\n if (req.method !== 'GET') {\n return res.status(405).json({ error: 'Method not allowed' })\n }\n const hostId = String(req.query['hostId'] ?? '')\n const mode = req.query['mode'] === 'past' ? 'past' : 'upcoming'\n if (!hostId) return res.status(400).json({ error: 'Missing hostId' })\n\n try {\n const firestore = firebaseAdmin.app().firestore()\n const hostRef = firestore.collection('hosts').doc(hostId)\n const hostSnapshot = await hostRef.get()\n if (!hostSnapshot.exists) {\n return res.status(404).json({ error: 'Unknown site' })\n }\n {\n // Plan/quota gates ride the owning org's doc (AGL-238).\n const org = (await getOrgForHost(hostId))?.org\n if (!checkEntitlement(org as never, 'eventCalendar')) {\n return res.status(200).json({ events: [] })\n }\n }\n\n /*\n * Only published events, ON THE QUERY, so the fifty it returns are fifty\n * a visitor may see rather than fifty by start time with the drafts then\n * dropped. `status` is written by every save (the console's one event\n * writer), and the delete writes `status: 'deleted'` beside `deletedAt`,\n * so `== 'published'` is both \"published\" and \"not deleted\". Served by\n * the `events (status, startsAtMs)` composites, one per direction, in\n * `cloud/firebase-firestore.indexes.json`.\n */\n const nowMs = Date.now()\n const published = hostRef\n .collection('events')\n .where('status', '==', 'published')\n const eventsQuery =\n mode === 'past'\n ? published\n .where('startsAtMs', '<', nowMs)\n .orderBy('startsAtMs', 'desc')\n .limit(EVENTS_LIST_LIMIT)\n : published\n .where('startsAtMs', '>=', nowMs)\n .orderBy('startsAtMs', 'asc')\n .limit(EVENTS_LIST_LIMIT)\n // The site's own identity, for absolutizing the cover below (AGL-1351).\n // The host doc is already in hand — this costs no read.\n const host = {\n $id: hostId,\n cname: hostSnapshot.get('cname') ?? null,\n subdomain: hostSnapshot.get('subdomain') ?? null,\n }\n\n const snapshot = await eventsQuery.get()\n const events = snapshot.docs\n // An event deleted before its delete also wrote `status` still reads\n // `published`; its `deletedAt` keeps it off the page.\n .filter((doc) => !doc.get('deletedAt'))\n .map((doc) => ({\n $id: doc.id,\n title: doc.get('title') ?? '',\n startsAtMs: Number(doc.get('startsAtMs') ?? 0),\n endsAtMs: Number(doc.get('endsAtMs') ?? 0),\n location: doc.get('location') ?? null,\n organizer: doc.get('organizer') ?? null,\n description: doc.get('description') ?? null,\n // ABSOLUTE, resolved here rather than shipped as stored (AGL-1351).\n //\n // \"Cover image URL\" is a free text field, so what an author types is\n // frequently a site-relative path — which the browser resolves against\n // the page and a crawler reading the `Event` JSON-LD cannot resolve at\n // all. That is the AGL-1337/AGL-1343 defect a third time over, and it\n // is fixed HERE because this is the only place that knows which site\n // the events belong to: `EventList` is a client block whose\n // `useSite()` carries a `hostId` and no origin, and in Preview the\n // page origin is the console's, not the site's.\n //\n // Absolutizing also repairs the visible thumbnail on that surface: a\n // relative cover in Preview resolved against the console and 404'd.\n coverImage:\n resolveSocialImage({\n sources: [{ image: doc.get('coverImage') }],\n host,\n })?.url ?? null,\n // The author's description of that cover (AGL-2418). Passed through\n // as stored — unlike the URL beside it there is nothing to resolve,\n // and the renderer owns the \"blank means decorative\" decision.\n coverImageAlt: doc.get('coverImageAlt') ?? null,\n }))\n // Cacheable: published events change rarely; CDN may hold for a minute.\n res.setHeader('Cache-Control', 'public, s-maxage=60')\n return res.status(200).json({ events })\n } catch (error) {\n console.error(error)\n return res.status(500).json({ error: 'Event listing failed' })\n }\n}\n\n/** Registers the events-calendar plugin's API routes with the dispatcher. */\n/**\n * Site-event dispatch (AGL-256): the page runtime evaluates client-side\n * trigger conditions (scroll thresholds, selectors, dwell time) and posts\n * the fired action here so its SERVER steps run. Only site-event actions\n * dispatch this way — server events keep their own emitters. Payload\n * fields are bounded strings; the run cap and `actions` entitlement gate\n * inside the runner.\n */\nconst eventsDispatchHandler: PluginApiHandler = async (req, res) => {\n if (req.method !== 'POST') {\n return res.status(405).json({ error: 'Method not allowed' })\n }\n const hostId = String(req.body?.hostId ?? '')\n const actionId = String(req.body?.actionId ?? '')\n const event = String(req.body?.event ?? '')\n if (!hostId || !actionId || !isSiteEventType(event)) {\n return res.status(400).json({ error: 'Bad dispatch' })\n }\n const raw = req.body?.payload\n const payload: Record<string, string> = {}\n if (raw && typeof raw === 'object') {\n for (const [key, value] of Object.entries(raw).slice(0, 20)) {\n if (/^[a-zA-Z][a-zA-Z0-9_]{0,39}$/.test(key)) {\n payload[key] = String(value).slice(0, 500)\n }\n }\n }\n const alerts = await dispatchHostAutomation(hostId, actionId, event, payload)\n return res.status(200).json({ ok: true, alerts })\n}\n\nexport function registerEventsCalendarApi(): void {\n registerPluginApiRoute('events/list', eventsListHandler)\n registerPluginApiRoute('events/dispatch', eventsDispatchHandler)\n}\n"],"names":["checkEntitlement","isSiteEventType","registerPluginApiRoute","resolveSocialImage","firebaseAdmin","getOrgForHost","dispatchHostAutomation","EVENTS_LIST_LIMIT","eventsListHandler","req","res","method","status","json","error","hostId","String","query","mode","hostSnapshot","firestore","app","hostRef","collection","doc","get","exists","org","events","nowMs","Date","now","published","where","eventsQuery","orderBy","limit","host","$id","cname","subdomain","snapshot","docs","filter","map","id","title","startsAtMs","Number","endsAtMs","location","organizer","description","coverImage","sources","image","url","coverImageAlt","setHeader","console","eventsDispatchHandler","body","actionId","event","raw","payload","key","value","Object","entries","slice","test","alerts","ok","registerEventsCalendarApi"],"mappings":"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"}
1
+ {"version":3,"sources":["../../../../../../libs/plugins/events-calendar/src/lib/server.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\n/**\n * Server half of the events-calendar plugin (AGL-396): the reference API\n * migration. Registers the public `events/list` handler with the plugin API\n * registry; the app dispatcher serves it at the unchanged `/api/events/list`\n * URL. This module imports firebase-admin, so it is NOT re-exported from the\n * plugin's client barrel — apps import `@aglyn/plugins-events-calendar/server`\n * only from their (server-only) API dispatcher.\n */\n\nimport {\n checkEntitlement,\n isSiteEventType,\n registerPluginApiRoute,\n resolveSocialImage,\n type PluginApiHandler,\n} from '@aglyn/aglyn/server'\nimport { firebaseAdmin, getOrgForHost } from '@aglyn/tenant-data-admin'\nimport { dispatchHostAutomation } from '@aglyn/tenant-runtime'\n\n/** How many events one listing returns. */\nconst EVENTS_LIST_LIMIT = 50\n\n/**\n * Public event listing (AGL-145): published events for the Event List canvas\n * element. Drafts never leave the server; the paid `eventCalendar` add-on\n * gates plan-holding workspaces (dark-launch workspaces pass). Sorted by start;\n * `mode=past` flips the window.\n */\nconst eventsListHandler: PluginApiHandler = async (req, res) => {\n if (req.method !== 'GET') {\n return res.status(405).json({ error: 'Method not allowed' })\n }\n const hostId = String(req.query['hostId'] ?? '')\n const mode = req.query['mode'] === 'past' ? 'past' : 'upcoming'\n if (!hostId) return res.status(400).json({ error: 'Missing hostId' })\n\n try {\n const firestore = firebaseAdmin.app().firestore()\n const hostRef = firestore.collection('hosts').doc(hostId)\n const hostSnapshot = await hostRef.get()\n if (!hostSnapshot.exists) {\n return res.status(404).json({ error: 'Unknown site' })\n }\n {\n // Plan/quota gates ride the owning org's doc (AGL-238).\n const org = (await getOrgForHost(hostId))?.org\n if (!checkEntitlement(org as never, 'eventCalendar')) {\n return res.status(200).json({ events: [] })\n }\n }\n\n /*\n * Only published events, ON THE QUERY, so the fifty it returns are fifty\n * a visitor may see rather than fifty by start time with the drafts then\n * dropped. `status` is written by every save (the console's one event\n * writer), and the delete writes `status: 'deleted'` beside `deletedAt`,\n * so `== 'published'` is both \"published\" and \"not deleted\". Served by\n * the `events (status, startsAtMs)` composites, one per direction, in\n * `cloud/firebase-firestore.indexes.json`.\n */\n const nowMs = Date.now()\n const published = hostRef\n .collection('events')\n .where('status', '==', 'published')\n const eventsQuery =\n mode === 'past'\n ? published\n .where('startsAtMs', '<', nowMs)\n .orderBy('startsAtMs', 'desc')\n .limit(EVENTS_LIST_LIMIT)\n : published\n .where('startsAtMs', '>=', nowMs)\n .orderBy('startsAtMs', 'asc')\n .limit(EVENTS_LIST_LIMIT)\n // The site's own identity, for absolutizing the cover below (AGL-1351).\n // The host doc is already in hand — this costs no read.\n const host = {\n $id: hostId,\n cname: hostSnapshot.get('cname') ?? null,\n subdomain: hostSnapshot.get('subdomain') ?? null,\n }\n\n const snapshot = await eventsQuery.get()\n const events = snapshot.docs\n // An event deleted before its delete also wrote `status` still reads\n // `published`; its `deletedAt` keeps it off the page.\n .filter((doc) => !doc.get('deletedAt'))\n .map((doc) => ({\n $id: doc.id,\n title: doc.get('title') ?? '',\n startsAtMs: Number(doc.get('startsAtMs') ?? 0),\n endsAtMs: Number(doc.get('endsAtMs') ?? 0),\n location: doc.get('location') ?? null,\n organizer: doc.get('organizer') ?? null,\n description: doc.get('description') ?? null,\n // ABSOLUTE, resolved here rather than shipped as stored (AGL-1351).\n //\n // \"Cover image URL\" is a free text field, so what an author types is\n // frequently a site-relative path — which the browser resolves against\n // the page and a crawler reading the `Event` JSON-LD cannot resolve at\n // all. That is the AGL-1337/AGL-1343 defect a third time over, and it\n // is fixed HERE because this is the only place that knows which site\n // the events belong to: `EventList` is a client block whose\n // `useSite()` carries a `hostId` and no origin, and in Preview the\n // page origin is the console's, not the site's.\n //\n // Absolutizing also repairs the visible thumbnail on that surface: a\n // relative cover in Preview resolved against the console and 404'd.\n coverImage:\n resolveSocialImage({\n sources: [{ image: doc.get('coverImage') }],\n host,\n })?.url ?? null,\n // The author's description of that cover (AGL-2418). Passed through\n // as stored — unlike the URL beside it there is nothing to resolve,\n // and the renderer owns the \"blank means decorative\" decision.\n coverImageAlt: doc.get('coverImageAlt') ?? null,\n }))\n // Cacheable: published events change rarely; CDN may hold for a minute.\n res.setHeader('Cache-Control', 'public, s-maxage=60')\n return res.status(200).json({ events })\n } catch (error) {\n console.error(error)\n return res.status(500).json({ error: 'Event listing failed' })\n }\n}\n\n/** Registers the events-calendar plugin's API routes with the dispatcher. */\n/**\n * Site-event dispatch (AGL-256): the page runtime evaluates client-side\n * trigger conditions (scroll thresholds, selectors, dwell time) and posts\n * the fired action here so its SERVER steps run. Only site-event actions\n * dispatch this way — server events keep their own emitters. Payload\n * fields are bounded strings; the run cap and `actions` entitlement gate\n * inside the runner.\n */\nconst eventsDispatchHandler: PluginApiHandler = async (req, res) => {\n if (req.method !== 'POST') {\n return res.status(405).json({ error: 'Method not allowed' })\n }\n const hostId = String(req.body?.hostId ?? '')\n const actionId = String(req.body?.actionId ?? '')\n const event = String(req.body?.event ?? '')\n if (!hostId || !actionId || !isSiteEventType(event)) {\n return res.status(400).json({ error: 'Bad dispatch' })\n }\n const raw = req.body?.payload\n const payload: Record<string, string> = {}\n if (raw && typeof raw === 'object') {\n for (const [key, value] of Object.entries(raw).slice(0, 20)) {\n if (/^[a-zA-Z][a-zA-Z0-9_]{0,39}$/.test(key)) {\n payload[key] = String(value).slice(0, 500)\n }\n }\n }\n // A visitor on the published page fired it (AGL-3376).\n const alerts = await dispatchHostAutomation(hostId, actionId, event, payload, {\n actor: { kind: 'visitor' },\n })\n return res.status(200).json({ ok: true, alerts })\n}\n\nexport function registerEventsCalendarApi(): void {\n registerPluginApiRoute('events/list', eventsListHandler)\n registerPluginApiRoute('events/dispatch', eventsDispatchHandler)\n}\n"],"names":["checkEntitlement","isSiteEventType","registerPluginApiRoute","resolveSocialImage","firebaseAdmin","getOrgForHost","dispatchHostAutomation","EVENTS_LIST_LIMIT","eventsListHandler","req","res","method","status","json","error","hostId","String","query","mode","hostSnapshot","firestore","app","hostRef","collection","doc","get","exists","org","events","nowMs","Date","now","published","where","eventsQuery","orderBy","limit","host","$id","cname","subdomain","snapshot","docs","filter","map","id","title","startsAtMs","Number","endsAtMs","location","organizer","description","coverImage","sources","image","url","coverImageAlt","setHeader","console","eventsDispatchHandler","body","actionId","event","raw","payload","key","value","Object","entries","slice","test","alerts","actor","kind","ok","registerEventsCalendarApi"],"mappings":"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"}