@go-labs-sg/event-tech 1.1.0 → 1.3.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.
Files changed (3) hide show
  1. package/README.md +52 -0
  2. package/dist/index.js +378 -2
  3. package/package.json +2 -2
package/README.md CHANGED
@@ -99,6 +99,58 @@ et lucky-draw participants list --event-id <id> --page 1 --per-page 100
99
99
 
100
100
  Commands emit deterministic JSON envelopes. Authentication credentials are never included in successful output, and bearer credentials are redacted from errors.
101
101
 
102
+ ### Event Passport
103
+
104
+ `et passport` uses the same typed procedures and event permissions as the web app.
105
+ Read `et --help` for all commands. Examples below use illustrative IDs and are not
106
+ an instruction to change a live event:
107
+
108
+ ```sh
109
+ et passport overview --event-id <id>
110
+ et passport login-options --event-id <id>
111
+ et passport mine --event-id <id>
112
+ et passport station upsert --event-id <id> --station-json '{"name":"Balance trail","collection":{"collectionMode":"STAFF_SCORE","maxPoints":20}}'
113
+ et passport station print-get --event-id <id> --station-id <id>
114
+ et passport station print-issue --event-id <id> --station-id <id> --expected-printed-qr-version <last-read-version>
115
+ et passport station print-revoke --event-id <id> --station-id <id> --expected-printed-qr-version <last-read-version> --allow-state-change --target <same-event-id>
116
+ et passport collect --event-id <id> --station-id <id> --profile-code <participant-code> --points 15
117
+ et passport claim --event-id <id> --code <station-code>
118
+ et passport participant detail --event-id <id> --participant-id <id>
119
+ et passport export --event-id <id>
120
+ ```
121
+
122
+ Station collection modes are `SELF_SCAN`, `STAFF_SCAN` and `STAFF_SCORE`.
123
+ `SELF_SCAN` uses a reusable printable QR; `STAFF_SCAN` is stamp-only; only
124
+ `STAFF_SCORE` accepts `collection.maxPoints` and a collection `--points` value.
125
+ Zero is valid. Repeat collection returns the original receipt without changing
126
+ points. Omit `collection` on an existing station edit to preserve its current
127
+ mode, including the legacy rotating-QR mode. Issuing/revoking printed codes uses
128
+ the last observed version to reject stale writes. Issue/rotation requires setup
129
+ permission; any event Operator can collect at any station.
130
+
131
+ `settings update --settings-json <json>` replaces the reward settings, so read
132
+ and copy the existing link, thresholds and redemption cap rather than clearing
133
+ them accidentally. Its JSON requires `linkedDrawEventId`,
134
+ `luckyDrawStampThreshold`, `prizeStampThreshold` and
135
+ `maxRedemptionsPerParticipant`; optional `loginMethods` is
136
+ `{"emailOtp":true,"google":false,"guest":true}`. Omit `loginMethods` to preserve
137
+ it. At least email OTP or Google must remain enabled for recovery, and enabling
138
+ Google requires configured provider credentials. Points never replace the
139
+ existing stamp-based reward thresholds.
140
+
141
+ `stamp correct`, `redemption reverse`, station/prize archive and print revocation
142
+ require `--allow-state-change --target <same-event-id>`; correction/reversal also
143
+ require a reason. Scored corrections accept `--points` and preserve historical
144
+ scores on revocation. Prize setup and redemption commands remain in `et --help`.
145
+ Participant reads/exports include points and nullable guest contact emails; do
146
+ not treat a null contact as an account lookup key.
147
+
148
+ Guest enrollment/account linking is browser-only: it requires the original guest
149
+ cookie and verified email/Google authentication. `mine` can read only the passport
150
+ owned by the current CLI identity; it cannot recover a guest by name or assume a
151
+ participant ID. No CLI auth transport or organiser access boundary is bypassed.
152
+ See the [Passport workflow and rollout gates](../../../docs/design/event-tech-passport-event-type.md).
153
+
102
154
  ### Deprecated event types
103
155
 
104
156
  Scavenger Hunt (Amazing Race) and Gardens by the Bay are deprecated and frozen.
package/dist/index.js CHANGED
@@ -35,7 +35,7 @@ var __toESM = (mod, isNodeMode, target) => {
35
35
  var __commonJS = (cb, mod) => () => (mod || cb((mod = { exports: {} }).exports, mod), mod.exports);
36
36
  var __require = import.meta.require;
37
37
 
38
- // ../../../node_modules/.bun/dotenv@18.0.8/node_modules/dotenv/dist/index.cjs
38
+ // ../../../node_modules/.bun/dotenv@18.0.9/node_modules/dotenv/dist/index.cjs
39
39
  var require_dist = __commonJS(function(exports, module) {
40
40
  var j = (e, n) => () => {
41
41
  try {
@@ -367,7 +367,7 @@ var require_dist = __commonJS(function(exports, module) {
367
367
  }
368
368
  function Ee(e) {
369
369
  let n = J(), t = { encoding: n.encoding || "utf8", quiet: n.quiet, debug: n.debug === true, override: n.override === true, fast: n.fast === true, paths: [".env"], defaultPath: true };
370
- return n.path != null && (t.paths = [n.path], t.defaultPath = false), e.pathSet && (t.paths = e.paths, t.defaultPath = false), e.quiet != null && (t.quiet = e.quiet), e.debug != null && (t.debug = e.debug), e.override != null && (t.override = e.override), e.fast != null && (t.fast = e.fast), t;
370
+ return n.path && (t.paths = [n.path], t.defaultPath = false), e.pathSet && (t.paths = e.paths, t.defaultPath = false), e.quiet != null && (t.quiet = e.quiet), e.debug != null && (t.debug = e.debug), e.override != null && (t.override = e.override), e.fast != null && (t.fast = e.fast), t;
371
371
  }
372
372
  function be(e) {
373
373
  let n = {}, t = [], o = { override: e.override, debug: e.debug };
@@ -6863,6 +6863,45 @@ Usage:
6863
6863
  et lucky-draw pre-draw --event-id <id> --prize-count <n>
6864
6864
  et lucky-draw participants replace --event-id <id> (--participants <json-array> | --participants-file <path>) --allow-state-change --target <same-event-id>
6865
6865
  et lucky-draw participants list --event-id <id> [--page <n>] [--per-page <n>]
6866
+ et passport overview --event-id <id>
6867
+ et passport mine --event-id <id>
6868
+ et passport login-options --event-id <id>
6869
+ et passport export --event-id <id>
6870
+ et passport settings update --event-id <id> --settings-json <json>
6871
+ et passport station upsert --event-id <id> --station-json <json>
6872
+ et passport station hidden --event-id <id> --station-id <id> --hidden <true|false>
6873
+ et passport station archive --event-id <id> --station-id <id> --allow-state-change --target <same-event-id>
6874
+ et passport station print-get --event-id <id> --station-id <id>
6875
+ et passport station print-issue --event-id <id> --station-id <id> --expected-printed-qr-version <n>
6876
+ et passport station print-revoke --event-id <id> --station-id <id> --expected-printed-qr-version <n> --allow-state-change --target <same-event-id>
6877
+ et passport station start-qr --event-id <id> --station-id <id>
6878
+ et passport station qr-status --event-id <id> --session-id <id>
6879
+ et passport collect --event-id <id> --station-id <id> --profile-code <code> [--points <n>]
6880
+ et passport claim --event-id <id> --code <code>
6881
+ et passport participant search --event-id <id> [--query <text>]
6882
+ et passport participant detail --event-id <id> --participant-id <id>
6883
+ et passport stamp correct --event-id <id> --station-id <id> --participant-id <id> --stamped <true|false> --reason <text> [--points <n>] --allow-state-change --target <same-event-id>
6884
+ et passport prize upsert --event-id <id> --prize-json <json>
6885
+ et passport prize archive --event-id <id> --prize-id <id> --allow-state-change --target <same-event-id>
6886
+ et passport redemption create --event-id <id> --participant-id <id> --prize-id <id>
6887
+ et passport redemption reverse --event-id <id> --redemption-id <id> --reason <text> --allow-state-change --target <same-event-id>
6888
+
6889
+ Event Passport:
6890
+ Uses the same typed procedures and event permissions as the web app.
6891
+ Station collection modes: SELF_SCAN, STAFF_SCAN, STAFF_SCORE.
6892
+ Include collection.maxPoints only for STAFF_SCORE; zero is a valid score.
6893
+ Omit collection on an existing station to preserve its current mode.
6894
+ Station JSON supports id/name/description/location/imageKey/order/opensAt/closesAt/collection.
6895
+ Date-time fields are ISO strings or null; order defaults to zero.
6896
+ Settings JSON requires linkedDrawEventId, luckyDrawStampThreshold, prizeStampThreshold,
6897
+ maxRedemptionsPerParticipant; optional loginMethods is {emailOtp,google,guest}.
6898
+ Keep email OTP or Google enabled for guest recovery. Omit loginMethods to preserve it.
6899
+ Printed QR issue/revoke requires the last observed print version; stale versions conflict.
6900
+ claim scans a station QR; collect scans a participant profile QR as an event operator.
6901
+ Repeat scans never add a second stamp or change its original points.
6902
+ Destructive corrections, archive, reverse and print revoke require explicit target confirmation.
6903
+ Points are scores only; existing stamp-based Lucky Draw and prize thresholds still apply.
6904
+ Guest enrollment and account-linking require the browser; CLI uses existing device-approved auth.
6866
6905
 
6867
6906
  Lucky draw:
6868
6907
  pre-draw immediately saves winners for the next unassigned prizes in order.
@@ -6933,6 +6972,334 @@ var writeError = (runtime, error) => {
6933
6972
  runtime.stderr.write(serialize({ ok: false, error: { code: errorCode(error), message } }));
6934
6973
  };
6935
6974
 
6975
+ // src/commands/passport.ts
6976
+ var flag = (flags, name, required = true) => {
6977
+ const value = flags.get(name);
6978
+ if (value === true || required && !value)
6979
+ throw new CliUsageError(`--${name} requires a value.`);
6980
+ return value;
6981
+ };
6982
+ var requiredFlag = (flags, name) => {
6983
+ const value = flag(flags, name);
6984
+ if (!value)
6985
+ throw new CliUsageError(`--${name} is required.`);
6986
+ return value;
6987
+ };
6988
+ var integer2 = (value, name, minimum = 0) => {
6989
+ const parsed = typeof value === "string" && value.trim() !== "" ? Number(value) : value;
6990
+ if (typeof parsed !== "number" || !Number.isSafeInteger(parsed) || parsed < minimum || parsed > 2147483647) {
6991
+ throw new CliUsageError(`${name} must be a whole number from ${minimum} to 2147483647.`);
6992
+ }
6993
+ return parsed;
6994
+ };
6995
+ var boolean3 = (value, name) => {
6996
+ if (value === true || value === "true")
6997
+ return true;
6998
+ if (value === false || value === "false")
6999
+ return false;
7000
+ throw new CliUsageError(`${name} must be true or false.`);
7001
+ };
7002
+ var text = (value, name, maximum) => {
7003
+ if (typeof value !== "string" || !value.trim() || value.trim().length > maximum)
7004
+ throw new CliUsageError(`${name} must be a non-empty string of at most ${maximum} characters.`);
7005
+ return value.trim();
7006
+ };
7007
+ var nullableText = (value, name, maximum) => {
7008
+ if (value == null)
7009
+ return null;
7010
+ if (typeof value !== "string" || value.trim().length > maximum)
7011
+ throw new CliUsageError(`${name} must be a string of at most ${maximum} characters or null.`);
7012
+ return value.trim();
7013
+ };
7014
+ var object2 = (value, name) => {
7015
+ if (typeof value !== "object" || value === null || Array.isArray(value))
7016
+ throw new CliUsageError(`${name} must be an object.`);
7017
+ return Object.fromEntries(Object.entries(value));
7018
+ };
7019
+ var json = (value, name) => {
7020
+ try {
7021
+ const parsed = JSON.parse(value);
7022
+ return object2(parsed, name);
7023
+ } catch (error) {
7024
+ if (error instanceof CliUsageError)
7025
+ throw error;
7026
+ throw new CliUsageError(`${name} must be valid JSON.`);
7027
+ }
7028
+ };
7029
+ var keys = (value, allowed, name) => {
7030
+ if (Object.keys(value).some((key) => !allowed.includes(key)))
7031
+ throw new CliUsageError(`${name} contains unsupported fields.`);
7032
+ };
7033
+ var date2 = (value, name) => {
7034
+ if (value == null)
7035
+ return null;
7036
+ if (typeof value !== "string" || !/^\d{4}-\d\d-\d\dT/.test(value))
7037
+ throw new CliUsageError(`${name} must be an ISO date-time or null.`);
7038
+ const parsed = new Date(value);
7039
+ if (Number.isNaN(parsed.getTime()))
7040
+ throw new CliUsageError(`${name} must be a valid ISO date-time.`);
7041
+ return parsed;
7042
+ };
7043
+ var parsePassportStationInput = (raw, eventId) => {
7044
+ const value = json(raw, "--station-json");
7045
+ keys(value, [
7046
+ "id",
7047
+ "name",
7048
+ "description",
7049
+ "location",
7050
+ "imageKey",
7051
+ "order",
7052
+ "opensAt",
7053
+ "closesAt",
7054
+ "collection"
7055
+ ], "Station");
7056
+ let collection;
7057
+ if (value.collection !== undefined) {
7058
+ const item = object2(value.collection, "collection");
7059
+ if (item.collectionMode === "STAFF_SCORE") {
7060
+ keys(item, ["collectionMode", "maxPoints"], "collection");
7061
+ collection = {
7062
+ collectionMode: "STAFF_SCORE",
7063
+ maxPoints: integer2(item.maxPoints, "maxPoints")
7064
+ };
7065
+ } else if (item.collectionMode === "SELF_SCAN" || item.collectionMode === "STAFF_SCAN") {
7066
+ keys(item, ["collectionMode"], "collection");
7067
+ collection = { collectionMode: item.collectionMode };
7068
+ } else
7069
+ throw new CliUsageError("collectionMode must be SELF_SCAN, STAFF_SCAN or STAFF_SCORE.");
7070
+ }
7071
+ return {
7072
+ eventId,
7073
+ ...value.id === undefined ? {} : { id: text(value.id, "id", 200) },
7074
+ name: text(value.name, "name", 100),
7075
+ description: nullableText(value.description, "description", 1000),
7076
+ location: nullableText(value.location, "location", 200),
7077
+ imageKey: nullableText(value.imageKey, "imageKey", 2048),
7078
+ order: integer2(value.order ?? 0, "order"),
7079
+ opensAt: date2(value.opensAt, "opensAt"),
7080
+ closesAt: date2(value.closesAt, "closesAt"),
7081
+ ...collection ? { collection } : {}
7082
+ };
7083
+ };
7084
+ var parsePassportSettingsInput = (raw, eventId) => {
7085
+ const value = json(raw, "--settings-json");
7086
+ keys(value, [
7087
+ "luckyDrawStampThreshold",
7088
+ "prizeStampThreshold",
7089
+ "maxRedemptionsPerParticipant",
7090
+ "linkedDrawEventId",
7091
+ "loginMethods"
7092
+ ], "Settings");
7093
+ const threshold = (item, name) => item === null ? null : integer2(item, name, 1);
7094
+ let loginMethods;
7095
+ if (value.loginMethods !== undefined) {
7096
+ const methods = object2(value.loginMethods, "loginMethods");
7097
+ keys(methods, ["emailOtp", "google", "guest"], "loginMethods");
7098
+ if (typeof methods.emailOtp !== "boolean" || typeof methods.google !== "boolean" || typeof methods.guest !== "boolean")
7099
+ throw new CliUsageError("loginMethods values must be JSON booleans.");
7100
+ loginMethods = {
7101
+ emailOtp: methods.emailOtp,
7102
+ google: methods.google,
7103
+ guest: methods.guest
7104
+ };
7105
+ if (!loginMethods.emailOtp && !loginMethods.google)
7106
+ throw new CliUsageError("Keep email OTP or Google available for recovery.");
7107
+ }
7108
+ if (value.linkedDrawEventId === undefined)
7109
+ throw new CliUsageError("linkedDrawEventId is required (use null to disable).");
7110
+ return {
7111
+ eventId,
7112
+ luckyDrawStampThreshold: threshold(value.luckyDrawStampThreshold, "luckyDrawStampThreshold"),
7113
+ prizeStampThreshold: threshold(value.prizeStampThreshold, "prizeStampThreshold"),
7114
+ maxRedemptionsPerParticipant: integer2(value.maxRedemptionsPerParticipant, "maxRedemptionsPerParticipant", 1),
7115
+ linkedDrawEventId: value.linkedDrawEventId === null ? null : text(value.linkedDrawEventId, "linkedDrawEventId", 200),
7116
+ ...loginMethods ? { loginMethods } : {}
7117
+ };
7118
+ };
7119
+ var runPassportCommand = async (input) => {
7120
+ const { flags, positionals } = input;
7121
+ const action = positionals.slice(1).join(" ");
7122
+ const allowed = ["event-id"];
7123
+ const eventId = requiredFlag(flags, "event-id");
7124
+ const event = { eventId };
7125
+ const station = () => ({
7126
+ eventId,
7127
+ stationId: requiredFlag(flags, "station-id")
7128
+ });
7129
+ const version = () => integer2(requiredFlag(flags, "expected-printed-qr-version"), "--expected-printed-qr-version");
7130
+ const confirm = () => {
7131
+ allowed.push("allow-state-change", "target");
7132
+ if (flags.get("allow-state-change") !== true || requiredFlag(flags, "target") !== eventId)
7133
+ throw new CliUsageError("This operation requires --allow-state-change and --target exactly equal to --event-id.");
7134
+ };
7135
+ let operation;
7136
+ switch (action) {
7137
+ case "overview":
7138
+ operation = () => api2.event.passport.getPassportOverview.query(event);
7139
+ break;
7140
+ case "mine":
7141
+ operation = () => api2.event.passport.getMyPassport.query(event);
7142
+ break;
7143
+ case "login-options":
7144
+ operation = () => api2.event.passport.getPassportLoginOptions.query(event);
7145
+ break;
7146
+ case "export":
7147
+ operation = () => api2.event.passport.getPassportExportData.query(event);
7148
+ break;
7149
+ case "settings update": {
7150
+ allowed.push("settings-json");
7151
+ const payload = parsePassportSettingsInput(requiredFlag(flags, "settings-json"), eventId);
7152
+ operation = () => api2.event.passport.updatePassportSettings.mutate(payload);
7153
+ break;
7154
+ }
7155
+ case "station upsert": {
7156
+ allowed.push("station-json");
7157
+ const payload = parsePassportStationInput(requiredFlag(flags, "station-json"), eventId);
7158
+ operation = () => api2.event.passport.upsertPassportStation.mutate(payload);
7159
+ break;
7160
+ }
7161
+ case "station print-get": {
7162
+ allowed.push("station-id");
7163
+ const payload = station();
7164
+ operation = () => api2.event.passport.getStationPrintQr.query(payload);
7165
+ break;
7166
+ }
7167
+ case "station print-issue":
7168
+ case "station print-revoke": {
7169
+ allowed.push("station-id", "expected-printed-qr-version");
7170
+ const payload = { ...station(), expectedPrintedQrVersion: version() };
7171
+ if (action === "station print-revoke")
7172
+ confirm();
7173
+ operation = action === "station print-issue" ? () => api2.event.passport.issueStationPrintQr.mutate(payload) : () => api2.event.passport.revokeStationPrintQr.mutate(payload);
7174
+ break;
7175
+ }
7176
+ case "station archive": {
7177
+ allowed.push("station-id");
7178
+ confirm();
7179
+ const payload = station();
7180
+ operation = () => api2.event.passport.archivePassportStation.mutate(payload);
7181
+ break;
7182
+ }
7183
+ case "station hidden": {
7184
+ allowed.push("station-id", "hidden");
7185
+ const payload = {
7186
+ ...station(),
7187
+ hidden: boolean3(requiredFlag(flags, "hidden"), "--hidden")
7188
+ };
7189
+ operation = () => api2.event.passport.setPassportStationHidden.mutate(payload);
7190
+ break;
7191
+ }
7192
+ case "station start-qr": {
7193
+ allowed.push("station-id");
7194
+ const payload = station();
7195
+ operation = () => api2.event.passport.startStationQr.mutate(payload);
7196
+ break;
7197
+ }
7198
+ case "station qr-status": {
7199
+ allowed.push("session-id");
7200
+ const payload = { eventId, sessionId: requiredFlag(flags, "session-id") };
7201
+ operation = () => api2.event.passport.getStationQrStatus.query(payload);
7202
+ break;
7203
+ }
7204
+ case "collect": {
7205
+ allowed.push("station-id", "profile-code", "points");
7206
+ const points = flag(flags, "points", false);
7207
+ const payload = {
7208
+ ...station(),
7209
+ profileCode: requiredFlag(flags, "profile-code"),
7210
+ ...points === undefined ? {} : { points: integer2(points, "--points") }
7211
+ };
7212
+ operation = () => api2.event.passport.collectPassportStampByStaff.mutate(payload);
7213
+ break;
7214
+ }
7215
+ case "claim": {
7216
+ allowed.push("code");
7217
+ const payload = { eventId, code: requiredFlag(flags, "code") };
7218
+ operation = () => api2.event.passport.claimPassportStamp.mutate(payload);
7219
+ break;
7220
+ }
7221
+ case "stamp correct": {
7222
+ allowed.push("station-id", "participant-id", "stamped", "reason", "points");
7223
+ confirm();
7224
+ const points = flag(flags, "points", false);
7225
+ const payload = {
7226
+ ...station(),
7227
+ participantId: requiredFlag(flags, "participant-id"),
7228
+ stamped: boolean3(requiredFlag(flags, "stamped"), "--stamped"),
7229
+ reason: requiredFlag(flags, "reason"),
7230
+ ...points === undefined ? {} : { points: integer2(points, "--points") }
7231
+ };
7232
+ operation = () => api2.event.passport.correctPassportStamp.mutate(payload);
7233
+ break;
7234
+ }
7235
+ case "participant detail": {
7236
+ allowed.push("participant-id");
7237
+ const payload = {
7238
+ eventId,
7239
+ participantId: requiredFlag(flags, "participant-id")
7240
+ };
7241
+ operation = () => api2.event.passport.getPassportParticipantDetail.query(payload);
7242
+ break;
7243
+ }
7244
+ case "participant search": {
7245
+ allowed.push("query");
7246
+ const payload = { eventId, query: flag(flags, "query", false) ?? "" };
7247
+ operation = () => api2.event.passport.searchPassportParticipants.query(payload);
7248
+ break;
7249
+ }
7250
+ case "prize upsert": {
7251
+ allowed.push("prize-json");
7252
+ const value = json(requiredFlag(flags, "prize-json"), "--prize-json");
7253
+ keys(value, ["id", "name", "description", "stock", "order"], "Prize");
7254
+ const payload = {
7255
+ eventId,
7256
+ ...value.id === undefined ? {} : { id: text(value.id, "id", 200) },
7257
+ name: text(value.name, "name", 100),
7258
+ description: nullableText(value.description, "description", 1000),
7259
+ stock: integer2(value.stock, "stock"),
7260
+ order: integer2(value.order ?? 0, "order")
7261
+ };
7262
+ operation = () => api2.event.passport.upsertPassportPrize.mutate(payload);
7263
+ break;
7264
+ }
7265
+ case "prize archive": {
7266
+ allowed.push("prize-id");
7267
+ confirm();
7268
+ const payload = { eventId, prizeId: requiredFlag(flags, "prize-id") };
7269
+ operation = () => api2.event.passport.archivePassportPrize.mutate(payload);
7270
+ break;
7271
+ }
7272
+ case "redemption create": {
7273
+ allowed.push("prize-id", "participant-id");
7274
+ const payload = {
7275
+ eventId,
7276
+ prizeId: requiredFlag(flags, "prize-id"),
7277
+ participantId: requiredFlag(flags, "participant-id")
7278
+ };
7279
+ operation = () => api2.event.passport.redeemPassportPrize.mutate(payload);
7280
+ break;
7281
+ }
7282
+ case "redemption reverse": {
7283
+ allowed.push("redemption-id", "reason");
7284
+ confirm();
7285
+ const payload = {
7286
+ eventId,
7287
+ redemptionId: requiredFlag(flags, "redemption-id"),
7288
+ reason: requiredFlag(flags, "reason")
7289
+ };
7290
+ operation = () => api2.event.passport.reversePassportRedemption.mutate(payload);
7291
+ break;
7292
+ }
7293
+ default:
7294
+ throw new CliUsageError("Unknown passport command. Run et --help for supported commands.");
7295
+ }
7296
+ const unknown = [...flags.keys()].filter((key) => key !== "api-url" && !allowed.includes(key));
7297
+ if (unknown.length)
7298
+ throw new CliUsageError(`Unknown option(s): ${unknown.map((key) => `--${key}`).join(", ")}.`);
7299
+ await input.authenticate();
7300
+ writeSuccess(input.runtime, await operation());
7301
+ };
7302
+
6936
7303
  // src/cli.ts
6937
7304
  var getInstalledCliVersion = () => {
6938
7305
  try {
@@ -7155,6 +7522,15 @@ var runCommand = async (parsed, runtime, credentialStore, apiBaseUrl, configureA
7155
7522
  writeSuccess(runtime, { version: cliVersion });
7156
7523
  return;
7157
7524
  }
7525
+ if (group === "passport") {
7526
+ await runPassportCommand({
7527
+ positionals: parsed.positionals,
7528
+ flags: parsed.flags,
7529
+ runtime,
7530
+ authenticate: ensureAuthentication
7531
+ });
7532
+ return;
7533
+ }
7158
7534
  if (group === "auth" && action === "login" && subAction === undefined) {
7159
7535
  assertPositionalCount(parsed, 2);
7160
7536
  assertOnlyFlags(parsed, ["no-browser"]);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@go-labs-sg/event-tech",
3
- "version": "1.1.0",
3
+ "version": "1.3.0",
4
4
  "description": "Event Tech CLI for managing Event Tech resources through the Go Labs API.",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",
@@ -17,7 +17,7 @@
17
17
  ],
18
18
  "dependencies": {
19
19
  "@trpc/client": "^11.19.0",
20
- "dotenv": "^18.0.8",
20
+ "dotenv": "^18.0.9",
21
21
  "superjson": "^2.2.6"
22
22
  },
23
23
  "engines": {