@go-labs-sg/rsvp 1.4.0 → 1.5.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +70 -0
- package/dist/index.js +41 -13
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -262,6 +262,14 @@ Replace illustrative IDs and revisions with current readback values. Deploy API
|
|
|
262
262
|
policy enforcement before clients; an old API does not understand this field.
|
|
263
263
|
No authentication, consent flags, command names, or credential protocol changes.
|
|
264
264
|
|
|
265
|
+
### Registration-flow choice labels
|
|
266
|
+
|
|
267
|
+
`SINGLE_SELECT`, `VISUAL_SINGLE_SELECT` and `MULTI_SELECT` choices accept a
|
|
268
|
+
trimmed `label` of 1–500 characters, so a required single-choice `MULTI_SELECT`
|
|
269
|
+
can show a full-sentence declaration beside its tick box. Choice `value` stays a
|
|
270
|
+
stable machine value of 1–160 characters. Older APIs reject labels over 160
|
|
271
|
+
characters; deploy the API before saving longer labels.
|
|
272
|
+
|
|
265
273
|
### Registration-flow date-limit messages
|
|
266
274
|
|
|
267
275
|
`DATE` and `DATETIME` custom fields accept optional
|
|
@@ -911,6 +919,49 @@ rsvp people registration update \
|
|
|
911
919
|
--payload '{"organizationId":"org_123","eventId":"evt_123","registrationId":"reg_123","expectedVersion":4,"reason":"Moved to finance table","seats":[{"registrationAttendeeId":"att_1","seatId":"seat_9"},{"registrationAttendeeId":"att_2","seatId":"seat_2"}],"seatChangeNotice":{"idempotencyKey":"4d68a320-013d-43c7-bfcc-d1126827d8c5"}}'
|
|
912
920
|
```
|
|
913
921
|
|
|
922
|
+
### Archive or cancel registrations
|
|
923
|
+
|
|
924
|
+
`people registration archive` and `people registration cancel` forward the same
|
|
925
|
+
permissioned, audited `event.bulkManageRegistrations` operation as the web app.
|
|
926
|
+
Both require server-side `rsvp.manage` permission and `--allow-state-change`;
|
|
927
|
+
`--target` must match the payload's **event ID**, not a registration ID.
|
|
928
|
+
|
|
929
|
+
Supply `organizationId`, `eventId`, an audit `reason` (3–500 characters after
|
|
930
|
+
trimming), and 1–100 unique `registrations`, each with `id` and its current
|
|
931
|
+
positive-integer `expectedVersion`. Get revisions from `people registration list`
|
|
932
|
+
or `people registration edit get`. The command sets `action` to `ARCHIVE` or
|
|
933
|
+
`CANCEL` when omitted; explicitly supplying any other action is rejected. Missing
|
|
934
|
+
or invalid fields, duplicate IDs and oversized batches fail before dispatch.
|
|
935
|
+
Stale revisions are checked by the server; refresh and review before retrying.
|
|
936
|
+
|
|
937
|
+
```sh
|
|
938
|
+
rsvp people registration archive \
|
|
939
|
+
--allow-state-change --target evt_123 \
|
|
940
|
+
--payload '{"organizationId":"org_123","eventId":"evt_123","reason":"Remove refunded test registrations","registrations":[{"id":"reg_123","expectedVersion":6},{"id":"reg_456","expectedVersion":2}]}'
|
|
941
|
+
|
|
942
|
+
rsvp people registration cancel \
|
|
943
|
+
--allow-state-change --target evt_123 \
|
|
944
|
+
--payload '{"organizationId":"org_123","eventId":"evt_123","reason":"Participant withdrew","registrations":[{"id":"reg_789","expectedVersion":3}]}'
|
|
945
|
+
```
|
|
946
|
+
|
|
947
|
+
- **Archive** sets `archivedAt` and removes the registrations from default lists
|
|
948
|
+
and exports. It also cancels active registrations through the normal release
|
|
949
|
+
path; this is not merely hiding an attending registration.
|
|
950
|
+
- **Cancel** cancels active registrations without changing `archivedAt`. Cancelled
|
|
951
|
+
registrations remain visible unless already archived.
|
|
952
|
+
- Both release consumed event capacity, active seat bookings and holds, cancel
|
|
953
|
+
session selections and waiting/offered waitlist entries, and run the existing
|
|
954
|
+
event/session waitlist maintenance. Released places may generate waitlist
|
|
955
|
+
offers and **emails to other participants**; neither command sends a
|
|
956
|
+
cancellation email to the affected registrants. No `--allow-email` flag is
|
|
957
|
+
required by these commands' existing `state-change` contract.
|
|
958
|
+
- Neither command automatically refunds a payment or deletes records. Payment,
|
|
959
|
+
refund and audit history are retained. Pending checkouts linked to a provider,
|
|
960
|
+
processing payments and payments requiring review must be reconciled first;
|
|
961
|
+
unlinked pending payment attempts are cancelled by the existing server logic.
|
|
962
|
+
- Use **Unarchive** below for archive visibility/fresh-response recovery, or
|
|
963
|
+
**Restore** for attending recovery. Unarchive does not undo cancellation.
|
|
964
|
+
|
|
914
965
|
### Unarchive for a fresh response versus attending Restore
|
|
915
966
|
|
|
916
967
|
`people registration unarchive` forwards the permissioned, audited
|
|
@@ -1011,6 +1062,25 @@ previous effects.
|
|
|
1011
1062
|
|
|
1012
1063
|
Optional `registrationEmail` and `registrationMasterList` presentation settings
|
|
1013
1064
|
are also written through `REGISTRATION_RULES`; omitted settings are preserved.
|
|
1065
|
+
|
|
1066
|
+
### Registration email sender
|
|
1067
|
+
|
|
1068
|
+
Confirmation and seat-change emails send from the server default
|
|
1069
|
+
(`RSVP_EMAIL_FROM`) unless the event sets a sender in `registrationEmail`:
|
|
1070
|
+
|
|
1071
|
+
- `senderName` changes only the display name.
|
|
1072
|
+
- `senderLocalPart` and `senderDomain` (set both or neither) change the address,
|
|
1073
|
+
for example `"senderLocalPart": "nelbd", "senderDomain": "getout.sg"` sends
|
|
1074
|
+
from `"NELBD Quest" <nelbd@getout.sg>`. `senderDomain` must be a Resend domain
|
|
1075
|
+
that is verified with sending enabled when the update is saved; list them with
|
|
1076
|
+
`rsvp event email sender-domains`. Invalid local parts, a missing half of the
|
|
1077
|
+
pair or an unverified domain are rejected.
|
|
1078
|
+
|
|
1079
|
+
`registrationEmail` replaces the whole presentation object, so read the current
|
|
1080
|
+
event first and resend every key you want to keep. Reply-to and support email
|
|
1081
|
+
are unchanged. If a saved domain is later unverified in Resend, those emails
|
|
1082
|
+
fail and are recorded as failed deliveries; they never fall back silently to a
|
|
1083
|
+
different sender. Fix the domain or remove the address fields to resume.
|
|
1014
1084
|
See `examples/amgen-rsvp-copy/registration-presentation-patch.json` and its README
|
|
1015
1085
|
for a reviewed activation fragment, output-key semantics, receipt/header behavior
|
|
1016
1086
|
and the separate deployment/configuration/live-send approval gates. No event
|
package/dist/index.js
CHANGED
|
@@ -7726,11 +7726,13 @@ var flowBlockBaseShape = {
|
|
|
7726
7726
|
title: string2().trim().min(1).max(240).optional(),
|
|
7727
7727
|
visibleWhen: eventFlowConditionGroupSchema.optional()
|
|
7728
7728
|
};
|
|
7729
|
+
var maxEventFlowChoiceLabelLength = 500;
|
|
7730
|
+
var maxEventFlowChoiceValueLength = 160;
|
|
7729
7731
|
var customFieldChoiceSchema = object({
|
|
7730
7732
|
assetId: eventFlowEntityIdSchema.optional(),
|
|
7731
7733
|
description: string2().trim().max(500).optional(),
|
|
7732
|
-
label: string2().trim().min(1).max(
|
|
7733
|
-
value: string2().trim().min(1).max(
|
|
7734
|
+
label: string2().trim().min(1).max(maxEventFlowChoiceLabelLength),
|
|
7735
|
+
value: string2().trim().min(1).max(maxEventFlowChoiceValueLength)
|
|
7734
7736
|
});
|
|
7735
7737
|
var maxEventFlowDateBoundMessageLength = 500;
|
|
7736
7738
|
var eventFlowDateBoundMessageSchema = string2().trim().min(1).max(maxEventFlowDateBoundMessageLength);
|
|
@@ -10109,10 +10111,17 @@ var PUBLIC_EVENT_VALIDATED_FONT_FAMILIES = [
|
|
|
10109
10111
|
"Zilla Slab Highlight"
|
|
10110
10112
|
];
|
|
10111
10113
|
|
|
10114
|
+
// ../validators/src/email-sender.ts
|
|
10115
|
+
var emailSenderLocalPartSchema = string2().trim().max(64, "Sender address must be 64 characters or fewer").regex(/^(?!.*\.\.)[a-z\d](?:[a-z\d._+-]{0,62}[a-z\d])?$/i, "Enter a valid sender address before @");
|
|
10116
|
+
var emailSenderDomainSchema = string2().trim().toLowerCase().regex(/^(?:[a-z\d](?:[a-z\d-]{0,61}[a-z\d])?\.)+[a-z]{2,63}$/, "Select a valid sending domain");
|
|
10117
|
+
var EMAIL_SENDER_PAIR_MESSAGE = "Choose a sender address and domain together";
|
|
10118
|
+
|
|
10112
10119
|
// ../validators/src/registration-email-presentation.ts
|
|
10113
10120
|
var registrationEmailPresentationSchema = strictObject({
|
|
10114
10121
|
layout: _enum(["DEFAULT", "GROUPED"]).default("DEFAULT"),
|
|
10115
10122
|
senderName: string2().trim().min(1).max(120).regex(/^[^<>\r\n]+$/).optional(),
|
|
10123
|
+
senderLocalPart: emailSenderLocalPartSchema.optional(),
|
|
10124
|
+
senderDomain: emailSenderDomainSchema.optional(),
|
|
10116
10125
|
introText: string2().trim().min(1).max(1e4).optional(),
|
|
10117
10126
|
menuDetailOutputKeys: array(string2().trim().min(1).max(120)).max(100).default([]),
|
|
10118
10127
|
submittedConsentOutputKeys: array(string2().trim().min(1).max(120)).max(100).default([]),
|
|
@@ -10120,6 +10129,13 @@ var registrationEmailPresentationSchema = strictObject({
|
|
|
10120
10129
|
useResubmissionFooter: boolean2().default(false),
|
|
10121
10130
|
supportEmail: email2().optional(),
|
|
10122
10131
|
showLuckyDrawId: boolean2().optional()
|
|
10132
|
+
}).superRefine((value, ctx) => {
|
|
10133
|
+
if (Boolean(value.senderLocalPart) !== Boolean(value.senderDomain))
|
|
10134
|
+
ctx.addIssue({
|
|
10135
|
+
code: "custom",
|
|
10136
|
+
message: EMAIL_SENDER_PAIR_MESSAGE,
|
|
10137
|
+
path: [value.senderDomain ? "senderLocalPart" : "senderDomain"]
|
|
10138
|
+
});
|
|
10123
10139
|
});
|
|
10124
10140
|
|
|
10125
10141
|
// ../validators/src/registration-master-list-presentation.ts
|
|
@@ -10734,8 +10750,8 @@ var emailCampaignDraftFieldsSchema = object({
|
|
|
10734
10750
|
audienceMode: _enum(["SEGMENT", "SELECTED"]).optional(),
|
|
10735
10751
|
selectedInviteeIds: array(string2().min(1)).max(1e4).optional(),
|
|
10736
10752
|
fromName: string2().trim().max(120, "From name must be 120 characters or fewer").regex(/^[^\r\n<>]*$/, "From name contains unsupported characters").optional(),
|
|
10737
|
-
fromSubDomain:
|
|
10738
|
-
fromDomain:
|
|
10753
|
+
fromSubDomain: emailSenderLocalPartSchema.optional(),
|
|
10754
|
+
fromDomain: emailSenderDomainSchema.optional(),
|
|
10739
10755
|
html: string2().trim().min(1, "Email body is required").max(1e5, "Email body is too long"),
|
|
10740
10756
|
name: string2().trim().min(1, "Campaign name is required").max(160, "Campaign name must be 160 characters or fewer"),
|
|
10741
10757
|
previewText: string2().trim().max(240, "Preview text must be 240 characters or fewer").optional(),
|
|
@@ -10753,7 +10769,7 @@ var validateSelectedCampaignAudience = (input, ctx) => {
|
|
|
10753
10769
|
ctx.addIssue({
|
|
10754
10770
|
code: "custom",
|
|
10755
10771
|
path: [input.fromDomain ? "fromSubDomain" : "fromDomain"],
|
|
10756
|
-
message:
|
|
10772
|
+
message: EMAIL_SENDER_PAIR_MESSAGE
|
|
10757
10773
|
});
|
|
10758
10774
|
};
|
|
10759
10775
|
var createEmailCampaignInputSchema = organizationEventByIdInputSchema.extend(emailCampaignDraftFieldsSchema.shape).superRefine(validateSelectedCampaignAudience);
|
|
@@ -12393,18 +12409,21 @@ var commands = {
|
|
|
12393
12409
|
summary: "Update a user's global role (--payload JSON)."
|
|
12394
12410
|
}
|
|
12395
12411
|
};
|
|
12396
|
-
var
|
|
12397
|
-
|
|
12398
|
-
|
|
12399
|
-
|
|
12400
|
-
|
|
12401
|
-
|
|
12412
|
+
var parseRegistrationManagementInput = (input, expectedAction) => {
|
|
12413
|
+
const inputSchema = bulkManageRegistrationsInputSchema.safeExtend({
|
|
12414
|
+
action: bulkManageRegistrationsInputSchema.shape.action.extract([
|
|
12415
|
+
expectedAction
|
|
12416
|
+
])
|
|
12417
|
+
});
|
|
12402
12418
|
const action = input ? Reflect.get(input, "action") : undefined;
|
|
12403
|
-
const parsed =
|
|
12419
|
+
const parsed = inputSchema.safeParse(input ? { ...input, action: action === undefined ? expectedAction : action } : input);
|
|
12404
12420
|
if (!parsed.success)
|
|
12405
12421
|
throw new CliUsageError(parsed.error.issues.map((issue) => `${issue.path.join(".")}: ${issue.message}`).join("; "));
|
|
12406
12422
|
return parsed.data;
|
|
12407
12423
|
};
|
|
12424
|
+
var parseArchiveRegistrationsInput = (input) => parseRegistrationManagementInput(input, "ARCHIVE");
|
|
12425
|
+
var parseCancelRegistrationsInput = (input) => parseRegistrationManagementInput(input, "CANCEL");
|
|
12426
|
+
var parseUnarchiveRegistrationsInput = (input) => parseRegistrationManagementInput(input, "RESTORE");
|
|
12408
12427
|
var payloadCommand = (operation, summary, effects = [], targetKey) => ({
|
|
12409
12428
|
effects,
|
|
12410
12429
|
operation,
|
|
@@ -12491,6 +12510,7 @@ Object.assign(commands, {
|
|
|
12491
12510
|
"event seating table delete": payloadCommand((api, input) => api.event.deleteSeatTable.mutate(input), "Delete a seating table (--payload JSON).", ["delete", "state-change"]),
|
|
12492
12511
|
"event seating layout update": payloadCommand((api, input) => api.event.updateSeatTableLayout.mutate(input), "Update the seating layout and floor plan (--payload JSON).", ["state-change"], "eventId"),
|
|
12493
12512
|
"event seating table update": payloadCommand((api, input) => api.event.updateSeatTable.mutate(input), "Update a seating table (--payload JSON).", ["delete", "state-change"], "tableId"),
|
|
12513
|
+
"event email sender-domains": eventScopeQueryCommand((api, input) => api.event.getEmailSenderDomains.query(input), "List verified Resend sending domains for campaign and registration email sender addresses."),
|
|
12494
12514
|
"event audience-tier list": eventScopeQueryCommand((api, input) => api.event.listAudienceTiers.query(input), "List event audience tiers and assignment counts."),
|
|
12495
12515
|
"event audience-tier create": payloadCommand((api, input) => api.event.createAudienceTier.mutate(input), "Create an event audience tier (--payload JSON).", ["state-change"], "eventId"),
|
|
12496
12516
|
"event audience-tier update": payloadCommand((api, input) => api.event.updateAudienceTier.mutate(input), "Update an event audience tier (--payload JSON).", ["state-change"], "tierId"),
|
|
@@ -12523,6 +12543,14 @@ Object.assign(commands, {
|
|
|
12523
12543
|
{ effect: "email", whenPayloadField: "seatChangeNotice" }
|
|
12524
12544
|
]
|
|
12525
12545
|
},
|
|
12546
|
+
"people registration archive": {
|
|
12547
|
+
...payloadCommand((api, input) => api.event.bulkManageRegistrations.mutate(parseArchiveRegistrationsInput(input)), "Archive up to 100 unique registrations with expectedVersion and reason (3\u2013500 characters); action defaults to ARCHIVE and other actions are rejected. Requires rsvp.manage; target the eventId. Cancels active registrations, releases capacity, seats and holds, cancels session selections and waitlist entries/offers, and hides archived rows from default lists/exports. Unresolved checkouts must be reconciled first; no automatic refund. Not a delete: payment, refund and audit history remain. No cancellation email; released places may trigger waitlist-offer emails (--payload JSON).", ["state-change"], "eventId"),
|
|
12548
|
+
validateInput: parseArchiveRegistrationsInput
|
|
12549
|
+
},
|
|
12550
|
+
"people registration cancel": {
|
|
12551
|
+
...payloadCommand((api, input) => api.event.bulkManageRegistrations.mutate(parseCancelRegistrationsInput(input)), "Cancel up to 100 unique registrations with expectedVersion and reason (3\u2013500 characters); action defaults to CANCEL and other actions are rejected. Requires rsvp.manage; target the eventId. Cancels active registrations, releases capacity, seats and holds, and cancels session selections and waitlist entries/offers without changing archive visibility. Unresolved checkouts must be reconciled first; no automatic refund. Not a delete: payment, refund and audit history remain. No cancellation email; released places may trigger waitlist-offer emails (--payload JSON).", ["state-change"], "eventId"),
|
|
12552
|
+
validateInput: parseCancelRegistrationsInput
|
|
12553
|
+
},
|
|
12526
12554
|
"people registration unarchive": {
|
|
12527
12555
|
...payloadCommand((api, input) => api.event.bulkManageRegistrations.mutate(parseUnarchiveRegistrationsInput(input)), "Unarchive up to 100 unique registrations with expectedVersion and reason; action defaults to RESTORE and other actions are rejected. Target the eventId. Eligible cancelled nonattending invitees can submit afresh; historical registration, payment and QR are not reinstated. Fresh submissions use normal checks and new payment/credentials; attending recovery uses people registration restore (--payload JSON).", ["state-change"], "eventId"),
|
|
12528
12556
|
validateInput: parseUnarchiveRegistrationsInput
|
|
@@ -12536,7 +12564,7 @@ Object.assign(commands, {
|
|
|
12536
12564
|
"event mine list": payloadCommand((api, input) => api.event.listMyEvents.query(input), "List the caller's events (--payload JSON)."),
|
|
12537
12565
|
"event reminder list": payloadCommand((api, input) => api.event.listReminderSegments.query(input), "List reminder segments (--payload JSON).", ["sensitive-data"]),
|
|
12538
12566
|
"event rsvp submit": payloadCommand((api, input) => api.event.submitRsvp.mutate(input), "Submit the caller's registration (--payload JSON).", ["sensitive-data", "state-change"]),
|
|
12539
|
-
"event setup step update": payloadCommand((api, input) => api.event.updateSetupStep.mutate(input), "Update one revision-checked event setup step (--payload JSON). REGISTRATION_RULES accepts registrationEmail presentation, registrationMasterList output-key ordering/omissions and seatChangeNotification automatic policy; omitted settings are preserved.", ["state-change"]),
|
|
12567
|
+
"event setup step update": payloadCommand((api, input) => api.event.updateSetupStep.mutate(input), "Update one revision-checked event setup step (--payload JSON). REGISTRATION_RULES accepts registrationEmail presentation (including senderName and a senderLocalPart+senderDomain address on a verified Resend sending domain), registrationMasterList output-key ordering/omissions and seatChangeNotification automatic policy; omitted settings are preserved.", ["state-change"]),
|
|
12540
12568
|
"event page update": payloadCommand((api, input) => api.event.updateSetupStep.mutate({
|
|
12541
12569
|
...input,
|
|
12542
12570
|
section: "DETAILS_PAGE"
|