@go-labs-sg/event-tech 1.2.0 → 1.4.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 +102 -0
- package/dist/index.js +732 -153
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -85,8 +85,10 @@ Use `EVENT_TECH_API_URL` or `--api-url` to target another HTTPS deployment. Plai
|
|
|
85
85
|
et --help
|
|
86
86
|
et organization list
|
|
87
87
|
et organization get --organization-id <id>
|
|
88
|
+
et organization create --name "Example Org" --owner-email owner@example.test --allowed-event-types LUCKY_DRAW
|
|
88
89
|
et event list --organization-id <id>
|
|
89
90
|
et event get --event-id <id>
|
|
91
|
+
et event create --organization-id <id> --name "Example Dinner" --type LUCKY_DRAW --location "Ballroom" --start 2026-11-20T18:00:00+08:00
|
|
90
92
|
et event appearance get --event-id <id>
|
|
91
93
|
et event appearance get --event-id <id> --public
|
|
92
94
|
et event appearance update --event-id <id> --appearance-version <n> --appearance '<json>'
|
|
@@ -95,6 +97,10 @@ et event appearance upload --event-id <id> --file ./background.mp4 --media-type
|
|
|
95
97
|
et event photo-wall display-items --event-id <id> --limit 30
|
|
96
98
|
et lucky-draw participants replace --event-id <id> --participants '[{"luckyDrawId":"illustrative-001","name":"Example Person","email":"example@example.test"}]' --allow-state-change --target <id>
|
|
97
99
|
et lucky-draw participants list --event-id <id> --page 1 --per-page 100
|
|
100
|
+
et lucky-draw config get --event-id <id>
|
|
101
|
+
et lucky-draw config update --event-id <id> --config '{"luckyDrawType":"SLOT"}'
|
|
102
|
+
et lucky-draw background upload --event-id <id> --file ./board.png --content-type image/png
|
|
103
|
+
et lucky-draw prizes list --event-id <id>
|
|
98
104
|
```
|
|
99
105
|
|
|
100
106
|
Commands emit deterministic JSON envelopes. Authentication credentials are never included in successful output, and bearer credentials are redacted from errors.
|
|
@@ -231,6 +237,102 @@ bun run packages/event-tech/cli/src/index.ts help
|
|
|
231
237
|
|
|
232
238
|
Building is not publication or permission to mutate live data. Use focused temporary business-behavior tests and the final pre-push gate from the shared workflow. Use this package's actual scripts; do not assume it has a command-artifact generator.
|
|
233
239
|
|
|
240
|
+
## Lucky draw setup from scratch
|
|
241
|
+
|
|
242
|
+
An admin can set up a lucky draw without the browser. Each command uses the
|
|
243
|
+
same tRPC procedure and permission as the web flow: `organization create` is
|
|
244
|
+
global-admin only, `event create` needs organization owner/admin (or global
|
|
245
|
+
admin), and config, background and prize writes need `event.setup`.
|
|
246
|
+
|
|
247
|
+
```sh
|
|
248
|
+
# 1. Organization (skip if it exists; check with `et organization get`).
|
|
249
|
+
et organization create --name "Example Org" \
|
|
250
|
+
--owner-email owner@example.test --allowed-event-types LUCKY_DRAW
|
|
251
|
+
|
|
252
|
+
# 2. LUCKY_DRAW event. The board row and default config are created with it.
|
|
253
|
+
et event create --organization-id <org-id> --name "Example Dinner" \
|
|
254
|
+
--type LUCKY_DRAW --location "Ballroom" \
|
|
255
|
+
--start 2026-11-20T18:00:00+08:00 --end 2026-11-20T23:00:00+08:00
|
|
256
|
+
|
|
257
|
+
# 3. 1920x1080 background (jpeg/png/webp/gif).
|
|
258
|
+
et lucky-draw background upload --event-id <event-id> \
|
|
259
|
+
--file ./board-1920x1080.png --content-type image/png
|
|
260
|
+
|
|
261
|
+
# 4. Slot mode plus theme. Preview first with --dry-run.
|
|
262
|
+
et lucky-draw config update --event-id <event-id> --config-file ./theme.json --dry-run
|
|
263
|
+
et lucky-draw config update --event-id <event-id> --config-file ./theme.json
|
|
264
|
+
|
|
265
|
+
# 5. Prizes, then the participant roster.
|
|
266
|
+
et lucky-draw prizes create --event-id <event-id> --prizes-file ./prizes.json
|
|
267
|
+
et lucky-draw participants replace --event-id <event-id> \
|
|
268
|
+
--participants-file ./participants.json --allow-state-change --target <event-id>
|
|
269
|
+
|
|
270
|
+
# 6. Read everything back.
|
|
271
|
+
et lucky-draw config get --event-id <event-id>
|
|
272
|
+
et lucky-draw prizes list --event-id <event-id>
|
|
273
|
+
```
|
|
274
|
+
|
|
275
|
+
`organization create` also emails an owner invitation to `--owner-email`;
|
|
276
|
+
`data.deliveryStatus` reports `sent` or `failed`. The name must be unique among
|
|
277
|
+
active organizations (case-insensitive), otherwise the API returns `CONFLICT`.
|
|
278
|
+
|
|
279
|
+
`event create` requires `--location` and `--start` because the API does. Dates
|
|
280
|
+
are ISO 8601 date-times; include an offset so the time is unambiguous.
|
|
281
|
+
|
|
282
|
+
### Config merge patch
|
|
283
|
+
|
|
284
|
+
`config update` reads the current config, applies only the keys you pass, and
|
|
285
|
+
saves the full result. Example `theme.json`:
|
|
286
|
+
|
|
287
|
+
```json
|
|
288
|
+
{
|
|
289
|
+
"luckyDrawType": "SLOT",
|
|
290
|
+
"backgroundPreset": "#050d24",
|
|
291
|
+
"title": "Lucky Draw",
|
|
292
|
+
"titleColor": "#ffffff",
|
|
293
|
+
"titleFont": "font-serif",
|
|
294
|
+
"slotBorderColor": "#67ddf2",
|
|
295
|
+
"slotTextColor": "#ffffff",
|
|
296
|
+
"slotPositionX": 600,
|
|
297
|
+
"slotPositionY": 420
|
|
298
|
+
}
|
|
299
|
+
```
|
|
300
|
+
|
|
301
|
+
Keys are validated with the API's `luckyDrawConfigSchema` before any request:
|
|
302
|
+
unknown keys, wrong types and invalid enum values (`luckyDrawType`:
|
|
303
|
+
`WHEEL|SLOT`; `segmentText`: `NAME|LUCKY_DRAW_ID|BOTH`) fail with a `USAGE`
|
|
304
|
+
error that names the field. Arrays such as `includeDomains` are replaced, not
|
|
305
|
+
appended. Fields missing from an older stored config fall back to the web
|
|
306
|
+
form's defaults. `--dry-run` prints `changedFields` and the merged config
|
|
307
|
+
without saving. It must be passed bare: `--dry-run=true` (or any
|
|
308
|
+
`--flag=value` form of a bare flag) is a `USAGE` error, never a write. Run `et --help` for the full key list; positions are pixels on
|
|
309
|
+
the 1920x1080 board.
|
|
310
|
+
|
|
311
|
+
### Background
|
|
312
|
+
|
|
313
|
+
`background upload` uploads through the same presigned
|
|
314
|
+
`lucky-draw/backgrounds` flow as the preview page, then stores the key in
|
|
315
|
+
`customBackgroundImage`. It prints the `config get` readback, where
|
|
316
|
+
`customBackgroundImage` is a signed `/api/images/...` URL relative to the
|
|
317
|
+
Event Tech app. `background clear --allow-state-change --target <event-id>`
|
|
318
|
+
unsets it.
|
|
319
|
+
|
|
320
|
+
### Prizes
|
|
321
|
+
|
|
322
|
+
`prizes create` appends after the last prize. Pass one prize with `--name`
|
|
323
|
+
(and optional `--description`) or many with `--prizes`/`--prizes-file`
|
|
324
|
+
(`[{"name":"Grand Prize","description":"Optional"}]`, up to 500).
|
|
325
|
+
|
|
326
|
+
`prizes update --prize-id <id> --name <text> [--description <text>]` renames a
|
|
327
|
+
prize. `prizes reorder --prize-ids <id,...>` must list every active prize ID
|
|
328
|
+
exactly once, in the new order.
|
|
329
|
+
|
|
330
|
+
`prizes delete --prize-ids <id,...> --allow-state-change --target <event-id>`
|
|
331
|
+
permanently deletes the prizes (the API hard-deletes them) and renumbers the
|
|
332
|
+
rest. A prize already assigned to a winner cannot be deleted (`CONFLICT`).
|
|
333
|
+
Before update, delete and reorder, the CLI checks that every prize ID belongs
|
|
334
|
+
to `--event-id`.
|
|
335
|
+
|
|
234
336
|
## Lucky draw participant source import
|
|
235
337
|
|
|
236
338
|
The participant import is an API-first rollout: use a deployment that includes
|
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.
|
|
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
|
|
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 };
|
|
@@ -1814,6 +1814,41 @@ var $ZodCheckEndsWith = /* @__PURE__ */ $constructor("$ZodCheckEndsWith", (inst,
|
|
|
1814
1814
|
});
|
|
1815
1815
|
};
|
|
1816
1816
|
});
|
|
1817
|
+
function handleCheckPropertyResult(result, payload, property) {
|
|
1818
|
+
if (result.issues.length) {
|
|
1819
|
+
payload.issues.push(...prefixIssues(property, result.issues));
|
|
1820
|
+
}
|
|
1821
|
+
}
|
|
1822
|
+
var $ZodCheckProperties = /* @__PURE__ */ $constructor("$ZodCheckProperties", (inst, def) => {
|
|
1823
|
+
$ZodCheck.init(inst, def);
|
|
1824
|
+
hide(inst, Symbol.iterator, function* () {
|
|
1825
|
+
yield inst;
|
|
1826
|
+
});
|
|
1827
|
+
let entries;
|
|
1828
|
+
inst._zod.check = (payload) => {
|
|
1829
|
+
if (payload.value == null) {
|
|
1830
|
+
payload.issues.push({ expected: "object", code: "invalid_type", input: payload.value, inst });
|
|
1831
|
+
return;
|
|
1832
|
+
}
|
|
1833
|
+
entries ?? (entries = Reflect.ownKeys(def.shape).map((key) => [key, def.shape[key]]));
|
|
1834
|
+
const input = payload.value;
|
|
1835
|
+
let proms;
|
|
1836
|
+
for (const [key, schema] of entries) {
|
|
1837
|
+
const result = schema._zod.run({ value: input[key], issues: [] }, {});
|
|
1838
|
+
if (result instanceof Promise) {
|
|
1839
|
+
proms ?? (proms = []);
|
|
1840
|
+
proms.push(result.then((result) => handleCheckPropertyResult(result, payload, key)));
|
|
1841
|
+
} else {
|
|
1842
|
+
handleCheckPropertyResult(result, payload, key);
|
|
1843
|
+
}
|
|
1844
|
+
}
|
|
1845
|
+
if (proms)
|
|
1846
|
+
return Promise.all(proms).then(() => {
|
|
1847
|
+
return;
|
|
1848
|
+
});
|
|
1849
|
+
return;
|
|
1850
|
+
};
|
|
1851
|
+
});
|
|
1817
1852
|
var $ZodCheckOverwrite = /* @__PURE__ */ $constructor("$ZodCheckOverwrite", (inst, def) => {
|
|
1818
1853
|
$ZodCheck.init(inst, def);
|
|
1819
1854
|
inst._zod.check = (payload) => {
|
|
@@ -4111,6 +4146,13 @@ function _endsWith(suffix, params) {
|
|
|
4111
4146
|
suffix
|
|
4112
4147
|
});
|
|
4113
4148
|
}
|
|
4149
|
+
function _properties(shape, params) {
|
|
4150
|
+
return new $ZodCheckProperties({
|
|
4151
|
+
check: "properties",
|
|
4152
|
+
shape,
|
|
4153
|
+
...normalizeParams(params)
|
|
4154
|
+
});
|
|
4155
|
+
}
|
|
4114
4156
|
function _overwrite(tx) {
|
|
4115
4157
|
return new $ZodCheckOverwrite({
|
|
4116
4158
|
check: "overwrite",
|
|
@@ -6060,6 +6102,35 @@ function refine(fn, _params = {}) {
|
|
|
6060
6102
|
function superRefine(fn, params) {
|
|
6061
6103
|
return _superRefine(fn, params);
|
|
6062
6104
|
}
|
|
6105
|
+
var ZodInstanceOf = /* @__PURE__ */ $constructor("ZodInstanceOf", (inst, def) => {
|
|
6106
|
+
ZodCustom.init(inst, def);
|
|
6107
|
+
}, {
|
|
6108
|
+
properties(shape, params) {
|
|
6109
|
+
return this.check(_properties(shape, params));
|
|
6110
|
+
}
|
|
6111
|
+
});
|
|
6112
|
+
function _instanceof(cls, params = {}) {
|
|
6113
|
+
const inst = new ZodInstanceOf({
|
|
6114
|
+
type: "custom",
|
|
6115
|
+
check: "custom",
|
|
6116
|
+
fn: (data) => data instanceof cls,
|
|
6117
|
+
abort: true,
|
|
6118
|
+
...normalizeParams(params)
|
|
6119
|
+
});
|
|
6120
|
+
inst._zod.bag.Class = cls;
|
|
6121
|
+
inst._zod.check = (payload) => {
|
|
6122
|
+
if (!(payload.value instanceof cls)) {
|
|
6123
|
+
payload.issues.push({
|
|
6124
|
+
code: "invalid_type",
|
|
6125
|
+
expected: cls.name,
|
|
6126
|
+
input: payload.value,
|
|
6127
|
+
inst,
|
|
6128
|
+
path: [...inst._zod.def.path ?? []]
|
|
6129
|
+
});
|
|
6130
|
+
}
|
|
6131
|
+
};
|
|
6132
|
+
return inst;
|
|
6133
|
+
}
|
|
6063
6134
|
// ../../cli-auth/src/protocol/schemas.ts
|
|
6064
6135
|
var dateTimeString = string2().refine((value) => Number.isFinite(Date.parse(value)), "Invalid datetime");
|
|
6065
6136
|
var base64Url2 = string2().min(43).max(128).regex(/^[A-Za-z0-9_-]+$/);
|
|
@@ -6754,8 +6825,30 @@ var logoutCliSession = async ({
|
|
|
6754
6825
|
};
|
|
6755
6826
|
// src/cli.ts
|
|
6756
6827
|
import { readFileSync } from "fs";
|
|
6757
|
-
import { readFile as
|
|
6758
|
-
import { basename, resolve } from "path";
|
|
6828
|
+
import { readFile as readFile4 } from "fs/promises";
|
|
6829
|
+
import { basename as basename2, resolve } from "path";
|
|
6830
|
+
|
|
6831
|
+
// ../db/src/generated/prisma/enums.ts
|
|
6832
|
+
var EventType = {
|
|
6833
|
+
POST_IT_NOTE: "POST_IT_NOTE",
|
|
6834
|
+
PHOTO_WALL: "PHOTO_WALL",
|
|
6835
|
+
STORY_COLLECTION: "STORY_COLLECTION",
|
|
6836
|
+
LUCKY_DRAW: "LUCKY_DRAW",
|
|
6837
|
+
SCAVENGER_HUNT: "SCAVENGER_HUNT",
|
|
6838
|
+
HUMAN_BINGO: "HUMAN_BINGO",
|
|
6839
|
+
SIGNATURE_WALL: "SIGNATURE_WALL",
|
|
6840
|
+
GARDENS_BY_THE_BAY: "GARDENS_BY_THE_BAY",
|
|
6841
|
+
RATING_SYSTEM: "RATING_SYSTEM",
|
|
6842
|
+
EVENT_PASSPORT: "EVENT_PASSPORT"
|
|
6843
|
+
};
|
|
6844
|
+
|
|
6845
|
+
// ../validators/src/event-type.schema.ts
|
|
6846
|
+
var DEPRECATED_EVENT_TYPES = [
|
|
6847
|
+
EventType.SCAVENGER_HUNT,
|
|
6848
|
+
EventType.GARDENS_BY_THE_BAY
|
|
6849
|
+
];
|
|
6850
|
+
var activeEventTypeSchema = _enum(EventType).exclude(DEPRECATED_EVENT_TYPES);
|
|
6851
|
+
var ACTIVE_EVENT_TYPES = activeEventTypeSchema.options;
|
|
6759
6852
|
|
|
6760
6853
|
// src/api-client.ts
|
|
6761
6854
|
import {
|
|
@@ -6841,6 +6934,193 @@ var api2 = new Proxy({}, {
|
|
|
6841
6934
|
get: (_target, property, receiver) => Reflect.get(property === "public" ? testingClient ?? activePublicClient : testingClient ?? activeClient, property, receiver)
|
|
6842
6935
|
});
|
|
6843
6936
|
|
|
6937
|
+
// src/arguments.ts
|
|
6938
|
+
import { readFile as readFile2 } from "fs/promises";
|
|
6939
|
+
|
|
6940
|
+
// src/runtime/index.ts
|
|
6941
|
+
var processRuntime = {
|
|
6942
|
+
stdout: process.stdout,
|
|
6943
|
+
stderr: process.stderr
|
|
6944
|
+
};
|
|
6945
|
+
|
|
6946
|
+
class CliUsageError extends Error {
|
|
6947
|
+
code = "USAGE";
|
|
6948
|
+
constructor(message) {
|
|
6949
|
+
super(message);
|
|
6950
|
+
this.name = "CliUsageError";
|
|
6951
|
+
}
|
|
6952
|
+
}
|
|
6953
|
+
var canonicalize = (value) => {
|
|
6954
|
+
if (Array.isArray(value))
|
|
6955
|
+
return value.map(canonicalize);
|
|
6956
|
+
if (value instanceof Date)
|
|
6957
|
+
return value.toJSON();
|
|
6958
|
+
if (typeof value === "object" && value !== null) {
|
|
6959
|
+
return Object.fromEntries(Object.entries(value).sort(([left], [right]) => left.localeCompare(right)).map(([key, nested]) => [key, canonicalize(nested)]));
|
|
6960
|
+
}
|
|
6961
|
+
return value;
|
|
6962
|
+
};
|
|
6963
|
+
var serialize = (value) => `${JSON.stringify(canonicalize(value), null, 2)}
|
|
6964
|
+
`;
|
|
6965
|
+
var writeSuccess = (runtime, data) => {
|
|
6966
|
+
runtime.stdout.write(serialize({ ok: true, data }));
|
|
6967
|
+
};
|
|
6968
|
+
var sanitizeErrorMessage = (message) => message.replace(/\bBearer\s+\S+/giu, "Bearer [REDACTED]");
|
|
6969
|
+
var errorCode = (error) => {
|
|
6970
|
+
if (error instanceof CliUsageError)
|
|
6971
|
+
return error.code;
|
|
6972
|
+
if (error instanceof CliConfigurationError)
|
|
6973
|
+
return error.code;
|
|
6974
|
+
if (typeof error === "object" && error !== null && "data" in error) {
|
|
6975
|
+
const data = error.data;
|
|
6976
|
+
if (typeof data === "object" && data !== null && "code" in data && typeof data.code === "string") {
|
|
6977
|
+
return data.code;
|
|
6978
|
+
}
|
|
6979
|
+
}
|
|
6980
|
+
return "INTERNAL_ERROR";
|
|
6981
|
+
};
|
|
6982
|
+
var writeError = (runtime, error) => {
|
|
6983
|
+
const storageError = getCliStorageError(error);
|
|
6984
|
+
if (storageError) {
|
|
6985
|
+
runtime.stderr.write(serialize({ ok: false, error: storageError }));
|
|
6986
|
+
return;
|
|
6987
|
+
}
|
|
6988
|
+
const message = error instanceof Error ? sanitizeErrorMessage(error.message) : "Unknown error.";
|
|
6989
|
+
runtime.stderr.write(serialize({ ok: false, error: { code: errorCode(error), message } }));
|
|
6990
|
+
};
|
|
6991
|
+
|
|
6992
|
+
// src/arguments.ts
|
|
6993
|
+
var booleanFlags = new Set([
|
|
6994
|
+
"allow-delete",
|
|
6995
|
+
"allow-state-change",
|
|
6996
|
+
"dry-run",
|
|
6997
|
+
"help",
|
|
6998
|
+
"no-browser",
|
|
6999
|
+
"public",
|
|
7000
|
+
"version"
|
|
7001
|
+
]);
|
|
7002
|
+
var parseArguments = (args) => {
|
|
7003
|
+
const positionals = [];
|
|
7004
|
+
const flags = new Map;
|
|
7005
|
+
for (let index = 0;index < args.length; index += 1) {
|
|
7006
|
+
const token = args[index];
|
|
7007
|
+
if (!token)
|
|
7008
|
+
continue;
|
|
7009
|
+
if (!token.startsWith("--")) {
|
|
7010
|
+
positionals.push(token);
|
|
7011
|
+
continue;
|
|
7012
|
+
}
|
|
7013
|
+
const [rawName, inlineValue] = token.slice(2).split("=", 2);
|
|
7014
|
+
if (!rawName)
|
|
7015
|
+
throw new CliUsageError("Flag names cannot be empty.");
|
|
7016
|
+
if (booleanFlags.has(rawName)) {
|
|
7017
|
+
if (inlineValue !== undefined) {
|
|
7018
|
+
throw new CliUsageError(`--${rawName} is a bare flag and does not take a value.`);
|
|
7019
|
+
}
|
|
7020
|
+
flags.set(rawName, true);
|
|
7021
|
+
continue;
|
|
7022
|
+
}
|
|
7023
|
+
if (inlineValue !== undefined) {
|
|
7024
|
+
flags.set(rawName, inlineValue);
|
|
7025
|
+
continue;
|
|
7026
|
+
}
|
|
7027
|
+
const nextValue = args[index + 1];
|
|
7028
|
+
if (nextValue && !nextValue.startsWith("--")) {
|
|
7029
|
+
flags.set(rawName, nextValue);
|
|
7030
|
+
index += 1;
|
|
7031
|
+
} else {
|
|
7032
|
+
flags.set(rawName, true);
|
|
7033
|
+
}
|
|
7034
|
+
}
|
|
7035
|
+
return { positionals, flags };
|
|
7036
|
+
};
|
|
7037
|
+
var getOptionalFlag = (parsed, name) => {
|
|
7038
|
+
const value = parsed.flags.get(name);
|
|
7039
|
+
if (value === undefined)
|
|
7040
|
+
return;
|
|
7041
|
+
if (value === true)
|
|
7042
|
+
throw new CliUsageError(`--${name} requires a value.`);
|
|
7043
|
+
return value;
|
|
7044
|
+
};
|
|
7045
|
+
var getRequiredFlag = (parsed, name) => {
|
|
7046
|
+
const value = getOptionalFlag(parsed, name);
|
|
7047
|
+
if (!value)
|
|
7048
|
+
throw new CliUsageError(`--${name} is required.`);
|
|
7049
|
+
return value;
|
|
7050
|
+
};
|
|
7051
|
+
var assertOnlyFlags = (parsed, allowedFlags) => {
|
|
7052
|
+
const allowed = new Set(["api-url", ...allowedFlags]);
|
|
7053
|
+
const unknown = [...parsed.flags.keys()].filter((name) => !allowed.has(name));
|
|
7054
|
+
if (unknown.length > 0) {
|
|
7055
|
+
throw new CliUsageError(`Unknown option${unknown.length === 1 ? "" : "s"}: ${unknown.map((name) => `--${name}`).join(", ")}.`);
|
|
7056
|
+
}
|
|
7057
|
+
};
|
|
7058
|
+
var assertPositionalCount = (parsed, expectedCount) => {
|
|
7059
|
+
if (parsed.positionals.length === expectedCount)
|
|
7060
|
+
return;
|
|
7061
|
+
throw new CliUsageError("Unexpected positional arguments.");
|
|
7062
|
+
};
|
|
7063
|
+
var assertStateChangeTarget = (parsed, eventId) => {
|
|
7064
|
+
if (parsed.flags.get("allow-state-change") !== true) {
|
|
7065
|
+
throw new CliUsageError("--allow-state-change is required as an explicit acknowledgement.");
|
|
7066
|
+
}
|
|
7067
|
+
if (getRequiredFlag(parsed, "target") !== eventId) {
|
|
7068
|
+
throw new CliUsageError("--target must exactly match --event-id.");
|
|
7069
|
+
}
|
|
7070
|
+
};
|
|
7071
|
+
var readInlineOrFile = async (parsed, inlineFlag, fileFlag) => {
|
|
7072
|
+
const inlineValue = getOptionalFlag(parsed, inlineFlag);
|
|
7073
|
+
const filePath = getOptionalFlag(parsed, fileFlag);
|
|
7074
|
+
if (inlineValue === undefined === (filePath === undefined)) {
|
|
7075
|
+
throw new CliUsageError(`Provide exactly one of --${inlineFlag} or --${fileFlag}.`);
|
|
7076
|
+
}
|
|
7077
|
+
if (inlineValue !== undefined)
|
|
7078
|
+
return inlineValue;
|
|
7079
|
+
try {
|
|
7080
|
+
return await readFile2(filePath, "utf8");
|
|
7081
|
+
} catch {
|
|
7082
|
+
throw new CliUsageError(`--${fileFlag} could not be read.`);
|
|
7083
|
+
}
|
|
7084
|
+
};
|
|
7085
|
+
var parseJsonValue = (value, name) => {
|
|
7086
|
+
try {
|
|
7087
|
+
return JSON.parse(value);
|
|
7088
|
+
} catch {
|
|
7089
|
+
throw new CliUsageError(`--${name} must be valid JSON.`);
|
|
7090
|
+
}
|
|
7091
|
+
};
|
|
7092
|
+
var parsePositiveInteger = (value, name) => {
|
|
7093
|
+
const parsed = Number(value);
|
|
7094
|
+
if (!Number.isSafeInteger(parsed) || parsed <= 0) {
|
|
7095
|
+
throw new CliUsageError(`--${name} must be a positive integer.`);
|
|
7096
|
+
}
|
|
7097
|
+
return parsed;
|
|
7098
|
+
};
|
|
7099
|
+
var parseNonnegativeInteger = (value, name) => {
|
|
7100
|
+
const parsed = Number(value);
|
|
7101
|
+
if (!Number.isSafeInteger(parsed) || parsed < 0) {
|
|
7102
|
+
throw new CliUsageError(`--${name} must be a non-negative integer.`);
|
|
7103
|
+
}
|
|
7104
|
+
return parsed;
|
|
7105
|
+
};
|
|
7106
|
+
var parseBoundedInteger = (value, name, minimum, maximum) => {
|
|
7107
|
+
const parsed = parsePositiveInteger(value, name);
|
|
7108
|
+
if (parsed > maximum || parsed < minimum) {
|
|
7109
|
+
throw new CliUsageError(`--${name} must be an integer from ${minimum} to ${maximum}.`);
|
|
7110
|
+
}
|
|
7111
|
+
return parsed;
|
|
7112
|
+
};
|
|
7113
|
+
var parseIdList = (value, name) => {
|
|
7114
|
+
const ids = value.split(",").map((id) => id.trim());
|
|
7115
|
+
if (ids.some((id) => id.length === 0)) {
|
|
7116
|
+
throw new CliUsageError(`--${name} must not contain blank entries.`);
|
|
7117
|
+
}
|
|
7118
|
+
if (new Set(ids).size !== ids.length) {
|
|
7119
|
+
throw new CliUsageError(`--${name} must not contain duplicates.`);
|
|
7120
|
+
}
|
|
7121
|
+
return ids;
|
|
7122
|
+
};
|
|
7123
|
+
|
|
6844
7124
|
// src/commands/index.ts
|
|
6845
7125
|
var usage = `Event Tech CLI
|
|
6846
7126
|
|
|
@@ -6853,13 +7133,24 @@ Usage:
|
|
|
6853
7133
|
et auth whoami
|
|
6854
7134
|
et organization list
|
|
6855
7135
|
et organization get --organization-id <id>
|
|
7136
|
+
et organization create --name <text> --owner-email <email> [--allowed-event-types <TYPE,...>]
|
|
6856
7137
|
et event list --organization-id <id> [--page <n>] [--per-page <n>] [--name <text>] [--status <status>] [--archive-status <status>]
|
|
6857
7138
|
et event get --event-id <id>
|
|
7139
|
+
et event create --organization-id <id> --name <text> --type <type> --location <text> --start <iso> [--end <iso>]
|
|
6858
7140
|
et event appearance get --event-id <id> [--public]
|
|
6859
7141
|
et event appearance update --event-id <id> --appearance-version <n> --appearance <json>
|
|
6860
7142
|
et event appearance reset --event-id <id> --appearance-version <n>
|
|
6861
7143
|
et event appearance upload --event-id <id> --file <path> --media-type <image|video> --content-type <mime>
|
|
6862
7144
|
et event photo-wall display-items --event-id <id> [--limit <n>] [--cursor <json>] [--retained-ids <json>]
|
|
7145
|
+
et lucky-draw config get --event-id <id>
|
|
7146
|
+
et lucky-draw config update --event-id <id> (--config <json> | --config-file <path>) [--dry-run]
|
|
7147
|
+
et lucky-draw background upload --event-id <id> --file <path> --content-type <image-mime>
|
|
7148
|
+
et lucky-draw background clear --event-id <id> --allow-state-change --target <same-event-id>
|
|
7149
|
+
et lucky-draw prizes list --event-id <id>
|
|
7150
|
+
et lucky-draw prizes create --event-id <id> (--name <text> [--description <text>] | --prizes <json-array> | --prizes-file <path>)
|
|
7151
|
+
et lucky-draw prizes update --event-id <id> --prize-id <id> --name <text> [--description <text>]
|
|
7152
|
+
et lucky-draw prizes delete --event-id <id> --prize-ids <id,...> --allow-state-change --target <same-event-id>
|
|
7153
|
+
et lucky-draw prizes reorder --event-id <id> --prize-ids <id,...>
|
|
6863
7154
|
et lucky-draw pre-draw --event-id <id> --prize-count <n>
|
|
6864
7155
|
et lucky-draw participants replace --event-id <id> (--participants <json-array> | --participants-file <path>) --allow-state-change --target <same-event-id>
|
|
6865
7156
|
et lucky-draw participants list --event-id <id> [--page <n>] [--per-page <n>]
|
|
@@ -6903,7 +7194,30 @@ Event Passport:
|
|
|
6903
7194
|
Points are scores only; existing stamp-based Lucky Draw and prize thresholds still apply.
|
|
6904
7195
|
Guest enrollment and account-linking require the browser; CLI uses existing device-approved auth.
|
|
6905
7196
|
|
|
7197
|
+
Organization and event setup:
|
|
7198
|
+
organization create is global-admin only. It provisions the org and emails an owner invitation
|
|
7199
|
+
to --owner-email; deliveryStatus reports whether that email was sent. Names must be unique.
|
|
7200
|
+
event create needs org owner/admin (or global admin). --type is an active event type such as
|
|
7201
|
+
LUCKY_DRAW; a LUCKY_DRAW event gets its board with default config automatically.
|
|
7202
|
+
--start/--end are ISO 8601 date-times with an offset, for example 2026-11-20T18:00:00+08:00.
|
|
7203
|
+
|
|
6906
7204
|
Lucky draw:
|
|
7205
|
+
config, background and prize writes need event.setup, the same as the web board settings.
|
|
7206
|
+
config update is a merge patch: only the given keys change. Unknown keys and wrong value types
|
|
7207
|
+
are rejected before any request. Arrays (includeDomains etc.) are replaced, not appended.
|
|
7208
|
+
--dry-run prints the merged config without saving it.
|
|
7209
|
+
Keys: title, titleColor, isTitleVisible, titleFontSize, titleFont, prizeColor, prizeFontSize,
|
|
7210
|
+
isPrizeVisible, prizeFont, luckyDrawType (WHEEL|SLOT), slotBackgroundColor, slotBorderColor,
|
|
7211
|
+
slotTextColor, slotFontSize, slotTextFont, backgroundPreset, customBackgroundImage,
|
|
7212
|
+
numberOfSegments, segmentPreset, segmentText (NAME|LUCKY_DRAW_ID|BOTH), wheelSegmentFont,
|
|
7213
|
+
wheelSegmentFontSize, wheelSegmentColorsPreset, includeDomains, excludeDomains, includeEmails,
|
|
7214
|
+
excludeEmails, titlePositionX/Y, slotPositionX/Y, prizePositionX/Y, prizeDivWidth, prizeDivHeight.
|
|
7215
|
+
Positions are pixels on the 1920x1080 board.
|
|
7216
|
+
background upload stores the image (jpeg/png/webp/gif) and sets customBackgroundImage;
|
|
7217
|
+
the readback contains a signed /api/images URL. background clear unsets it.
|
|
7218
|
+
prizes create appends after the last prize; --prizes takes [{"name","description"?}].
|
|
7219
|
+
prizes delete permanently removes unassigned prizes and renumbers the rest.
|
|
7220
|
+
prizes reorder takes every active prize ID once, in the new order.
|
|
6907
7221
|
pre-draw immediately saves winners for the next unassigned prizes in order.
|
|
6908
7222
|
Uses the live draw random selection and participant filters in the backend.
|
|
6909
7223
|
participants replace replaces the imported source roster; it is not an append.
|
|
@@ -6911,6 +7225,8 @@ Lucky draw:
|
|
|
6911
7225
|
participants list defaults to page 1 with 100 results per page; inspect every page.
|
|
6912
7226
|
|
|
6913
7227
|
Global options:
|
|
7228
|
+
Bare flags (--dry-run, --allow-state-change, --public, --no-browser) take no value;
|
|
7229
|
+
--flag=value spellings are rejected before any request.
|
|
6914
7230
|
--api-url <url> Override EVENT_TECH_API_URL.
|
|
6915
7231
|
--help Print this help as JSON.
|
|
6916
7232
|
--version Print the CLI version as JSON.
|
|
@@ -6920,56 +7236,351 @@ Authentication:
|
|
|
6920
7236
|
Credentials are stored exclusively through Bun.secrets.
|
|
6921
7237
|
EVENT_TECH_API_URL defaults to ${DEFAULT_EVENT_TECH_API_BASE_URL}.`;
|
|
6922
7238
|
|
|
6923
|
-
// src/
|
|
6924
|
-
|
|
6925
|
-
|
|
6926
|
-
|
|
7239
|
+
// src/commands/lucky-draw-setup.ts
|
|
7240
|
+
import { readFile as readFile3 } from "fs/promises";
|
|
7241
|
+
import { basename } from "path";
|
|
7242
|
+
|
|
7243
|
+
// ../db/src/lucky-draw-config-json.ts
|
|
7244
|
+
var LuckyDrawSegmentText = {
|
|
7245
|
+
NAME: "NAME",
|
|
7246
|
+
LUCKY_DRAW_ID: "LUCKY_DRAW_ID",
|
|
7247
|
+
BOTH: "BOTH"
|
|
7248
|
+
};
|
|
7249
|
+
var LuckyDrawType = {
|
|
7250
|
+
WHEEL: "WHEEL",
|
|
7251
|
+
SLOT: "SLOT"
|
|
6927
7252
|
};
|
|
6928
7253
|
|
|
6929
|
-
|
|
6930
|
-
|
|
6931
|
-
|
|
6932
|
-
|
|
6933
|
-
|
|
7254
|
+
// ../validators/src/lucky-draw/lucky-draw-config.schema.ts
|
|
7255
|
+
var luckyDrawConfigSchema = object({
|
|
7256
|
+
title: string2(),
|
|
7257
|
+
titleColor: string2(),
|
|
7258
|
+
isTitleVisible: boolean2(),
|
|
7259
|
+
titleFontSize: number2(),
|
|
7260
|
+
prizeColor: string2(),
|
|
7261
|
+
prizeFontSize: number2(),
|
|
7262
|
+
isPrizeVisible: boolean2(),
|
|
7263
|
+
slotBackgroundColor: string2(),
|
|
7264
|
+
slotBorderColor: string2(),
|
|
7265
|
+
slotTextColor: string2(),
|
|
7266
|
+
slotFontSize: number2(),
|
|
7267
|
+
wheelSegmentColorsPreset: string2(),
|
|
7268
|
+
backgroundPreset: string2(),
|
|
7269
|
+
numberOfSegments: number2(),
|
|
7270
|
+
includeDomains: array(string2()),
|
|
7271
|
+
excludeDomains: array(string2()),
|
|
7272
|
+
includeEmails: array(string2()),
|
|
7273
|
+
excludeEmails: array(string2()),
|
|
7274
|
+
segmentPreset: string2(),
|
|
7275
|
+
segmentText: _enum([
|
|
7276
|
+
LuckyDrawSegmentText.NAME,
|
|
7277
|
+
LuckyDrawSegmentText.LUCKY_DRAW_ID,
|
|
7278
|
+
LuckyDrawSegmentText.BOTH
|
|
7279
|
+
]),
|
|
7280
|
+
luckyDrawType: _enum([LuckyDrawType.WHEEL, LuckyDrawType.SLOT]),
|
|
7281
|
+
titleFont: string2(),
|
|
7282
|
+
prizeFont: string2(),
|
|
7283
|
+
wheelSegmentFont: string2(),
|
|
7284
|
+
wheelSegmentFontSize: number2(),
|
|
7285
|
+
slotTextFont: string2(),
|
|
7286
|
+
customBackgroundImage: string2().optional().nullable(),
|
|
7287
|
+
titlePositionX: number2(),
|
|
7288
|
+
titlePositionY: number2(),
|
|
7289
|
+
slotPositionX: number2(),
|
|
7290
|
+
slotPositionY: number2(),
|
|
7291
|
+
prizePositionX: number2(),
|
|
7292
|
+
prizePositionY: number2(),
|
|
7293
|
+
prizeDivWidth: number2(),
|
|
7294
|
+
prizeDivHeight: number2()
|
|
7295
|
+
});
|
|
7296
|
+
|
|
7297
|
+
// ../validators/src/lucky-draw/lucky-draw-config-input.schema.ts
|
|
7298
|
+
var luckyDrawConfigInputProcedureSchema = object({
|
|
7299
|
+
eventId: string2(),
|
|
7300
|
+
config: luckyDrawConfigSchema
|
|
7301
|
+
});
|
|
7302
|
+
var luckyDrawConfigInputSchema = object({
|
|
7303
|
+
...luckyDrawConfigSchema.omit({ customBackgroundImage: true }).shape,
|
|
7304
|
+
customBackgroundImage: union([_instanceof(File), string2()]).optional().nullable()
|
|
7305
|
+
});
|
|
7306
|
+
var DEFAULT_LUCKY_DRAW_CONFIG_INPUT_VALUES = {
|
|
7307
|
+
title: "Lucky Draw Title",
|
|
7308
|
+
titleColor: "#111111",
|
|
7309
|
+
isTitleVisible: true,
|
|
7310
|
+
titleFontSize: 40,
|
|
7311
|
+
prizeColor: "#111111",
|
|
7312
|
+
prizeFontSize: 30,
|
|
7313
|
+
isPrizeVisible: true,
|
|
7314
|
+
slotBackgroundColor: "#ffffff",
|
|
7315
|
+
slotBorderColor: "#ffffff",
|
|
7316
|
+
slotTextColor: "#111111",
|
|
7317
|
+
slotFontSize: 5,
|
|
7318
|
+
backgroundPreset: "#ede9fe",
|
|
7319
|
+
numberOfSegments: 12,
|
|
7320
|
+
includeDomains: [],
|
|
7321
|
+
excludeDomains: [],
|
|
7322
|
+
includeEmails: [],
|
|
7323
|
+
excludeEmails: [],
|
|
7324
|
+
segmentPreset: "Vibrant",
|
|
7325
|
+
segmentText: LuckyDrawSegmentText.NAME,
|
|
7326
|
+
luckyDrawType: LuckyDrawType.WHEEL,
|
|
7327
|
+
titleFont: "font-sans",
|
|
7328
|
+
prizeFont: "font-sans",
|
|
7329
|
+
wheelSegmentFont: "font-sans",
|
|
7330
|
+
wheelSegmentFontSize: 12,
|
|
7331
|
+
slotTextFont: "font-sans",
|
|
7332
|
+
customBackgroundImage: null,
|
|
7333
|
+
titlePositionX: 750,
|
|
7334
|
+
titlePositionY: 100,
|
|
7335
|
+
slotPositionX: 600,
|
|
7336
|
+
slotPositionY: 300,
|
|
7337
|
+
prizePositionX: 800,
|
|
7338
|
+
prizePositionY: 200,
|
|
7339
|
+
prizeDivWidth: 500,
|
|
7340
|
+
prizeDivHeight: 100,
|
|
7341
|
+
wheelSegmentColorsPreset: "Vibrant"
|
|
7342
|
+
};
|
|
7343
|
+
|
|
7344
|
+
// ../validators/src/lucky-draw/lucky-draw-prize-input.schema.ts
|
|
7345
|
+
var luckyDrawPrizeInputSchema = object({
|
|
7346
|
+
name: string2().min(1),
|
|
7347
|
+
description: string2().optional()
|
|
7348
|
+
});
|
|
7349
|
+
var multipleLuckyDrawPrizeInputSchema = object({
|
|
7350
|
+
eventId: string2().min(1, "EventID is required"),
|
|
7351
|
+
prizes: array(luckyDrawPrizeInputSchema)
|
|
7352
|
+
});
|
|
7353
|
+
|
|
7354
|
+
// src/commands/lucky-draw-setup.ts
|
|
7355
|
+
var LUCKY_DRAW_BACKGROUND_FOLDER = "lucky-draw/backgrounds";
|
|
7356
|
+
var luckyDrawConfigPatchSchema = luckyDrawConfigSchema.partial().strict();
|
|
7357
|
+
var formatIssues = (label, issues) => `${label} is invalid: ${issues.map((issue) => {
|
|
7358
|
+
const path = issue.path.map(String).join(".");
|
|
7359
|
+
return path ? `${path}: ${issue.message}` : issue.message;
|
|
7360
|
+
}).join("; ")}.`;
|
|
7361
|
+
var parseLuckyDrawConfigPatch = (raw) => {
|
|
7362
|
+
const value = parseJsonValue(raw, "config");
|
|
7363
|
+
if (typeof value !== "object" || value === null || Array.isArray(value)) {
|
|
7364
|
+
throw new CliUsageError("--config must be a JSON object.");
|
|
7365
|
+
}
|
|
7366
|
+
const result = luckyDrawConfigPatchSchema.safeParse(value);
|
|
7367
|
+
if (!result.success) {
|
|
7368
|
+
throw new CliUsageError(formatIssues("--config", result.error.issues));
|
|
7369
|
+
}
|
|
7370
|
+
if (Object.keys(result.data).length === 0) {
|
|
7371
|
+
throw new CliUsageError("--config must change at least one field.");
|
|
7372
|
+
}
|
|
7373
|
+
return result.data;
|
|
7374
|
+
};
|
|
7375
|
+
var mergeLuckyDrawConfig = (current, patch) => {
|
|
7376
|
+
const merged = {
|
|
7377
|
+
...DEFAULT_LUCKY_DRAW_CONFIG_INPUT_VALUES,
|
|
7378
|
+
...current ?? {},
|
|
7379
|
+
...patch
|
|
7380
|
+
};
|
|
7381
|
+
const result = luckyDrawConfigSchema.safeParse(merged);
|
|
7382
|
+
if (!result.success) {
|
|
7383
|
+
throw new CliUsageError(formatIssues("Merged lucky draw config", result.error.issues));
|
|
6934
7384
|
}
|
|
6935
|
-
|
|
6936
|
-
|
|
6937
|
-
|
|
6938
|
-
|
|
6939
|
-
if (value
|
|
6940
|
-
|
|
6941
|
-
if (typeof value === "object" && value !== null) {
|
|
6942
|
-
return Object.fromEntries(Object.entries(value).sort(([left], [right]) => left.localeCompare(right)).map(([key, nested]) => [key, canonicalize(nested)]));
|
|
7385
|
+
return result.data;
|
|
7386
|
+
};
|
|
7387
|
+
var parsePrizeList = (raw) => {
|
|
7388
|
+
const value = parseJsonValue(raw, "prizes");
|
|
7389
|
+
if (!Array.isArray(value) || value.length === 0) {
|
|
7390
|
+
throw new CliUsageError("--prizes must be a non-empty JSON array.");
|
|
6943
7391
|
}
|
|
6944
|
-
|
|
7392
|
+
if (value.length > 500) {
|
|
7393
|
+
throw new CliUsageError("--prizes must contain at most 500 prizes.");
|
|
7394
|
+
}
|
|
7395
|
+
return value.map((item, index) => {
|
|
7396
|
+
const result = luckyDrawPrizeInputSchema.strict().safeParse(item);
|
|
7397
|
+
if (!result.success) {
|
|
7398
|
+
throw new CliUsageError(formatIssues(`--prizes[${index}]`, result.error.issues));
|
|
7399
|
+
}
|
|
7400
|
+
return result.data;
|
|
7401
|
+
});
|
|
6945
7402
|
};
|
|
6946
|
-
var
|
|
6947
|
-
|
|
6948
|
-
var
|
|
6949
|
-
|
|
7403
|
+
var loadCurrentConfig = async (eventId) => (await api2.event.luckyDraw.getLuckyDrawByEventId.query({ eventId })).config;
|
|
7404
|
+
var loadPrizes = async (eventId) => (await api2.event.luckyDraw.getLuckyDrawPrizesByEventId.query({ eventId })).prizes;
|
|
7405
|
+
var assertPrizesBelongToEvent = (prizes, prizeIds, eventId) => {
|
|
7406
|
+
const known = new Set(prizes.map((prize) => prize.id));
|
|
7407
|
+
const missing = prizeIds.filter((id) => !known.has(id));
|
|
7408
|
+
if (missing.length > 0) {
|
|
7409
|
+
throw new CliUsageError(`Prize ID(s) not found on event ${eventId}: ${missing.join(", ")}.`);
|
|
7410
|
+
}
|
|
6950
7411
|
};
|
|
6951
|
-
var
|
|
6952
|
-
var
|
|
6953
|
-
|
|
6954
|
-
|
|
6955
|
-
if (
|
|
6956
|
-
|
|
6957
|
-
|
|
6958
|
-
const
|
|
6959
|
-
|
|
6960
|
-
|
|
7412
|
+
var saveConfig = (eventId, config) => api2.event.luckyDraw.updateLuckyDrawConfigJson.mutate({ eventId, config });
|
|
7413
|
+
var runLuckyDrawSetupCommand = async (input) => {
|
|
7414
|
+
const { parsed, runtime, authenticate } = input;
|
|
7415
|
+
const [, action, subAction] = parsed.positionals;
|
|
7416
|
+
if (action === "config" && subAction === "get") {
|
|
7417
|
+
assertPositionalCount(parsed, 3);
|
|
7418
|
+
assertOnlyFlags(parsed, ["event-id"]);
|
|
7419
|
+
const eventId = getRequiredFlag(parsed, "event-id");
|
|
7420
|
+
await authenticate();
|
|
7421
|
+
writeSuccess(runtime, await api2.event.luckyDraw.getLuckyDrawByEventId.query({ eventId }));
|
|
7422
|
+
return true;
|
|
7423
|
+
}
|
|
7424
|
+
if (action === "config" && subAction === "update") {
|
|
7425
|
+
assertPositionalCount(parsed, 3);
|
|
7426
|
+
assertOnlyFlags(parsed, ["event-id", "config", "config-file", "dry-run"]);
|
|
7427
|
+
const eventId = getRequiredFlag(parsed, "event-id");
|
|
7428
|
+
const patch = parseLuckyDrawConfigPatch(await readInlineOrFile(parsed, "config", "config-file"));
|
|
7429
|
+
await authenticate();
|
|
7430
|
+
const config = mergeLuckyDrawConfig(await loadCurrentConfig(eventId), patch);
|
|
7431
|
+
if (parsed.flags.get("dry-run") === true) {
|
|
7432
|
+
writeSuccess(runtime, {
|
|
7433
|
+
dryRun: true,
|
|
7434
|
+
changedFields: Object.keys(patch).sort(),
|
|
7435
|
+
config
|
|
7436
|
+
});
|
|
7437
|
+
return true;
|
|
6961
7438
|
}
|
|
7439
|
+
writeSuccess(runtime, await saveConfig(eventId, config));
|
|
7440
|
+
return true;
|
|
6962
7441
|
}
|
|
6963
|
-
|
|
6964
|
-
|
|
6965
|
-
|
|
6966
|
-
|
|
6967
|
-
|
|
6968
|
-
|
|
6969
|
-
|
|
7442
|
+
if (action === "background" && subAction === "upload") {
|
|
7443
|
+
assertPositionalCount(parsed, 3);
|
|
7444
|
+
assertOnlyFlags(parsed, ["event-id", "file", "content-type"]);
|
|
7445
|
+
const eventId = getRequiredFlag(parsed, "event-id");
|
|
7446
|
+
const filePath = getRequiredFlag(parsed, "file");
|
|
7447
|
+
const contentType = getRequiredFlag(parsed, "content-type");
|
|
7448
|
+
if (!contentType.startsWith("image/")) {
|
|
7449
|
+
throw new CliUsageError("--content-type must be an image MIME type.");
|
|
7450
|
+
}
|
|
7451
|
+
let file;
|
|
7452
|
+
try {
|
|
7453
|
+
file = await readFile3(filePath);
|
|
7454
|
+
} catch {
|
|
7455
|
+
throw new CliUsageError("--file could not be read.");
|
|
7456
|
+
}
|
|
7457
|
+
await authenticate();
|
|
7458
|
+
const signed = await api2.attachment.getPresignedUrlToUpload.mutate({
|
|
7459
|
+
folder: LUCKY_DRAW_BACKGROUND_FOLDER,
|
|
7460
|
+
fileName: basename(filePath),
|
|
7461
|
+
contentType,
|
|
7462
|
+
size: file.byteLength,
|
|
7463
|
+
eventId
|
|
7464
|
+
});
|
|
7465
|
+
const uploadResponse = await fetch(signed.uploadUrl, {
|
|
7466
|
+
method: "PUT",
|
|
7467
|
+
headers: { "content-type": contentType },
|
|
7468
|
+
body: file
|
|
7469
|
+
});
|
|
7470
|
+
if (!uploadResponse.ok) {
|
|
7471
|
+
throw new Error(`Lucky draw background upload failed with HTTP ${uploadResponse.status}.`);
|
|
7472
|
+
}
|
|
7473
|
+
const config = mergeLuckyDrawConfig(await loadCurrentConfig(eventId), {
|
|
7474
|
+
customBackgroundImage: signed.key
|
|
7475
|
+
});
|
|
7476
|
+
await saveConfig(eventId, config);
|
|
7477
|
+
writeSuccess(runtime, await api2.event.luckyDraw.getLuckyDrawByEventId.query({ eventId }));
|
|
7478
|
+
return true;
|
|
6970
7479
|
}
|
|
6971
|
-
|
|
6972
|
-
|
|
7480
|
+
if (action === "background" && subAction === "clear") {
|
|
7481
|
+
assertPositionalCount(parsed, 3);
|
|
7482
|
+
assertOnlyFlags(parsed, ["event-id", "allow-state-change", "target"]);
|
|
7483
|
+
const eventId = getRequiredFlag(parsed, "event-id");
|
|
7484
|
+
assertStateChangeTarget(parsed, eventId);
|
|
7485
|
+
await authenticate();
|
|
7486
|
+
const config = mergeLuckyDrawConfig(await loadCurrentConfig(eventId), {
|
|
7487
|
+
customBackgroundImage: null
|
|
7488
|
+
});
|
|
7489
|
+
writeSuccess(runtime, await saveConfig(eventId, config));
|
|
7490
|
+
return true;
|
|
7491
|
+
}
|
|
7492
|
+
if (action === "prizes" && subAction === "list") {
|
|
7493
|
+
assertPositionalCount(parsed, 3);
|
|
7494
|
+
assertOnlyFlags(parsed, ["event-id"]);
|
|
7495
|
+
const eventId = getRequiredFlag(parsed, "event-id");
|
|
7496
|
+
await authenticate();
|
|
7497
|
+
writeSuccess(runtime, await api2.event.luckyDraw.getLuckyDrawPrizesByEventId.query({ eventId }));
|
|
7498
|
+
return true;
|
|
7499
|
+
}
|
|
7500
|
+
if (action === "prizes" && subAction === "create") {
|
|
7501
|
+
assertPositionalCount(parsed, 3);
|
|
7502
|
+
assertOnlyFlags(parsed, [
|
|
7503
|
+
"event-id",
|
|
7504
|
+
"name",
|
|
7505
|
+
"description",
|
|
7506
|
+
"prizes",
|
|
7507
|
+
"prizes-file"
|
|
7508
|
+
]);
|
|
7509
|
+
const eventId = getRequiredFlag(parsed, "event-id");
|
|
7510
|
+
const name = getOptionalFlag(parsed, "name");
|
|
7511
|
+
const description = getOptionalFlag(parsed, "description");
|
|
7512
|
+
const hasList = parsed.flags.has("prizes") || parsed.flags.has("prizes-file");
|
|
7513
|
+
if (hasList === (name !== undefined)) {
|
|
7514
|
+
throw new CliUsageError("Provide either --name [--description] or one of --prizes / --prizes-file.");
|
|
7515
|
+
}
|
|
7516
|
+
if (hasList && description !== undefined) {
|
|
7517
|
+
throw new CliUsageError("--description is only valid with --name; include descriptions in the --prizes JSON.");
|
|
7518
|
+
}
|
|
7519
|
+
const prizes = hasList ? parsePrizeList(await readInlineOrFile(parsed, "prizes", "prizes-file")) : parsePrizeList(JSON.stringify([
|
|
7520
|
+
{ name, ...description === undefined ? {} : { description } }
|
|
7521
|
+
]));
|
|
7522
|
+
await authenticate();
|
|
7523
|
+
writeSuccess(runtime, await api2.event.luckyDraw.createLuckyDrawPrize.mutate({
|
|
7524
|
+
eventId,
|
|
7525
|
+
prizes
|
|
7526
|
+
}));
|
|
7527
|
+
return true;
|
|
7528
|
+
}
|
|
7529
|
+
if (action === "prizes" && subAction === "update") {
|
|
7530
|
+
assertPositionalCount(parsed, 3);
|
|
7531
|
+
assertOnlyFlags(parsed, ["event-id", "prize-id", "name", "description"]);
|
|
7532
|
+
const eventId = getRequiredFlag(parsed, "event-id");
|
|
7533
|
+
const prizeId = getRequiredFlag(parsed, "prize-id");
|
|
7534
|
+
const name = getRequiredFlag(parsed, "name");
|
|
7535
|
+
const description = getOptionalFlag(parsed, "description");
|
|
7536
|
+
await authenticate();
|
|
7537
|
+
assertPrizesBelongToEvent(await loadPrizes(eventId), [prizeId], eventId);
|
|
7538
|
+
writeSuccess(runtime, await api2.event.luckyDraw.updateLuckyDrawPrize.mutate({
|
|
7539
|
+
id: prizeId,
|
|
7540
|
+
name,
|
|
7541
|
+
...description === undefined ? {} : { description }
|
|
7542
|
+
}));
|
|
7543
|
+
return true;
|
|
7544
|
+
}
|
|
7545
|
+
if (action === "prizes" && subAction === "delete") {
|
|
7546
|
+
assertPositionalCount(parsed, 3);
|
|
7547
|
+
assertOnlyFlags(parsed, [
|
|
7548
|
+
"event-id",
|
|
7549
|
+
"prize-ids",
|
|
7550
|
+
"allow-state-change",
|
|
7551
|
+
"target"
|
|
7552
|
+
]);
|
|
7553
|
+
const eventId = getRequiredFlag(parsed, "event-id");
|
|
7554
|
+
const prizeIds = parseIdList(getRequiredFlag(parsed, "prize-ids"), "prize-ids");
|
|
7555
|
+
assertStateChangeTarget(parsed, eventId);
|
|
7556
|
+
await authenticate();
|
|
7557
|
+
assertPrizesBelongToEvent(await loadPrizes(eventId), prizeIds, eventId);
|
|
7558
|
+
writeSuccess(runtime, await api2.event.luckyDraw.deleteLuckyDrawPrize.mutate({ prizeIds }));
|
|
7559
|
+
return true;
|
|
7560
|
+
}
|
|
7561
|
+
if (action === "prizes" && subAction === "reorder") {
|
|
7562
|
+
assertPositionalCount(parsed, 3);
|
|
7563
|
+
assertOnlyFlags(parsed, ["event-id", "prize-ids"]);
|
|
7564
|
+
const eventId = getRequiredFlag(parsed, "event-id");
|
|
7565
|
+
const prizeIds = parseIdList(getRequiredFlag(parsed, "prize-ids"), "prize-ids");
|
|
7566
|
+
await authenticate();
|
|
7567
|
+
const prizes = await loadPrizes(eventId);
|
|
7568
|
+
assertPrizesBelongToEvent(prizes, prizeIds, eventId);
|
|
7569
|
+
if (prizeIds.length !== prizes.length) {
|
|
7570
|
+
throw new CliUsageError(`--prize-ids must list all ${prizes.length} active prizes in the new order.`);
|
|
7571
|
+
}
|
|
7572
|
+
const namesById = new Map(prizes.map((prize) => [prize.id, prize.name]));
|
|
7573
|
+
writeSuccess(runtime, await api2.event.luckyDraw.updateLuckyDrawPrizesOrder.mutate({
|
|
7574
|
+
eventId,
|
|
7575
|
+
prizes: prizeIds.map((id, order) => ({
|
|
7576
|
+
id,
|
|
7577
|
+
order,
|
|
7578
|
+
name: namesById.get(id) ?? ""
|
|
7579
|
+
}))
|
|
7580
|
+
}));
|
|
7581
|
+
return true;
|
|
7582
|
+
}
|
|
7583
|
+
return false;
|
|
6973
7584
|
};
|
|
6974
7585
|
|
|
6975
7586
|
// src/commands/passport.ts
|
|
@@ -7309,93 +7920,6 @@ var getInstalledCliVersion = () => {
|
|
|
7309
7920
|
return "unknown";
|
|
7310
7921
|
}
|
|
7311
7922
|
};
|
|
7312
|
-
var booleanFlags = new Set([
|
|
7313
|
-
"allow-delete",
|
|
7314
|
-
"allow-state-change",
|
|
7315
|
-
"help",
|
|
7316
|
-
"no-browser",
|
|
7317
|
-
"public",
|
|
7318
|
-
"version"
|
|
7319
|
-
]);
|
|
7320
|
-
var parseArguments = (args) => {
|
|
7321
|
-
const positionals = [];
|
|
7322
|
-
const flags = new Map;
|
|
7323
|
-
for (let index = 0;index < args.length; index += 1) {
|
|
7324
|
-
const token = args[index];
|
|
7325
|
-
if (!token)
|
|
7326
|
-
continue;
|
|
7327
|
-
if (!token.startsWith("--")) {
|
|
7328
|
-
positionals.push(token);
|
|
7329
|
-
continue;
|
|
7330
|
-
}
|
|
7331
|
-
const [rawName, inlineValue] = token.slice(2).split("=", 2);
|
|
7332
|
-
if (!rawName)
|
|
7333
|
-
throw new CliUsageError("Flag names cannot be empty.");
|
|
7334
|
-
if (inlineValue !== undefined) {
|
|
7335
|
-
flags.set(rawName, inlineValue);
|
|
7336
|
-
continue;
|
|
7337
|
-
}
|
|
7338
|
-
if (booleanFlags.has(rawName)) {
|
|
7339
|
-
flags.set(rawName, true);
|
|
7340
|
-
continue;
|
|
7341
|
-
}
|
|
7342
|
-
const nextValue = args[index + 1];
|
|
7343
|
-
if (nextValue && !nextValue.startsWith("--")) {
|
|
7344
|
-
flags.set(rawName, nextValue);
|
|
7345
|
-
index += 1;
|
|
7346
|
-
} else {
|
|
7347
|
-
flags.set(rawName, true);
|
|
7348
|
-
}
|
|
7349
|
-
}
|
|
7350
|
-
return { positionals, flags };
|
|
7351
|
-
};
|
|
7352
|
-
var getOptionalFlag = (parsed, name) => {
|
|
7353
|
-
const value = parsed.flags.get(name);
|
|
7354
|
-
if (value === undefined)
|
|
7355
|
-
return;
|
|
7356
|
-
if (value === true)
|
|
7357
|
-
throw new CliUsageError(`--${name} requires a value.`);
|
|
7358
|
-
return value;
|
|
7359
|
-
};
|
|
7360
|
-
var getRequiredFlag = (parsed, name) => {
|
|
7361
|
-
const value = getOptionalFlag(parsed, name);
|
|
7362
|
-
if (!value)
|
|
7363
|
-
throw new CliUsageError(`--${name} is required.`);
|
|
7364
|
-
return value;
|
|
7365
|
-
};
|
|
7366
|
-
var assertOnlyFlags = (parsed, allowedFlags) => {
|
|
7367
|
-
const allowed = new Set(["api-url", ...allowedFlags]);
|
|
7368
|
-
const unknown = [...parsed.flags.keys()].filter((name) => !allowed.has(name));
|
|
7369
|
-
if (unknown.length > 0) {
|
|
7370
|
-
throw new CliUsageError(`Unknown option${unknown.length === 1 ? "" : "s"}: ${unknown.map((name) => `--${name}`).join(", ")}.`);
|
|
7371
|
-
}
|
|
7372
|
-
};
|
|
7373
|
-
var assertPositionalCount = (parsed, expectedCount) => {
|
|
7374
|
-
if (parsed.positionals.length === expectedCount)
|
|
7375
|
-
return;
|
|
7376
|
-
throw new CliUsageError("Unexpected positional arguments.");
|
|
7377
|
-
};
|
|
7378
|
-
var parsePositiveInteger = (value, name) => {
|
|
7379
|
-
const parsed = Number(value);
|
|
7380
|
-
if (!Number.isSafeInteger(parsed) || parsed <= 0) {
|
|
7381
|
-
throw new CliUsageError(`--${name} must be a positive integer.`);
|
|
7382
|
-
}
|
|
7383
|
-
return parsed;
|
|
7384
|
-
};
|
|
7385
|
-
var parseNonnegativeInteger = (value, name) => {
|
|
7386
|
-
const parsed = Number(value);
|
|
7387
|
-
if (!Number.isSafeInteger(parsed) || parsed < 0) {
|
|
7388
|
-
throw new CliUsageError(`--${name} must be a non-negative integer.`);
|
|
7389
|
-
}
|
|
7390
|
-
return parsed;
|
|
7391
|
-
};
|
|
7392
|
-
var parseBoundedInteger = (value, name, minimum, maximum) => {
|
|
7393
|
-
const parsed = parsePositiveInteger(value, name);
|
|
7394
|
-
if (parsed > maximum || parsed < minimum) {
|
|
7395
|
-
throw new CliUsageError(`--${name} must be an integer from ${minimum} to ${maximum}.`);
|
|
7396
|
-
}
|
|
7397
|
-
return parsed;
|
|
7398
|
-
};
|
|
7399
7923
|
var parseJsonObject = (value, name) => {
|
|
7400
7924
|
let parsed;
|
|
7401
7925
|
try {
|
|
@@ -7475,13 +7999,6 @@ var parseLuckyDrawParticipants = (value) => {
|
|
|
7475
7999
|
};
|
|
7476
8000
|
});
|
|
7477
8001
|
};
|
|
7478
|
-
var readParticipantsFile = async (path) => {
|
|
7479
|
-
try {
|
|
7480
|
-
return await readFile2(path, "utf8");
|
|
7481
|
-
} catch {
|
|
7482
|
-
throw new CliUsageError("--participants-file could not be read.");
|
|
7483
|
-
}
|
|
7484
|
-
};
|
|
7485
8002
|
var parseAppearanceMediaType = (value) => {
|
|
7486
8003
|
if (value === "image" || value === "video")
|
|
7487
8004
|
return value;
|
|
@@ -7501,6 +8018,33 @@ var parseArchiveStatus = (value) => {
|
|
|
7501
8018
|
}
|
|
7502
8019
|
return value;
|
|
7503
8020
|
};
|
|
8021
|
+
var parseCreatableEventType = (value) => {
|
|
8022
|
+
const result = activeEventTypeSchema.safeParse(value);
|
|
8023
|
+
if (!result.success) {
|
|
8024
|
+
throw new CliUsageError(`--type must be one of: ${activeEventTypeSchema.options.join(", ")}.`);
|
|
8025
|
+
}
|
|
8026
|
+
return result.data;
|
|
8027
|
+
};
|
|
8028
|
+
var parseEventTypeList = (value) => {
|
|
8029
|
+
const types = value.split(",").map((type) => type.trim());
|
|
8030
|
+
return [...new Set(types)].map((type) => {
|
|
8031
|
+
const result = activeEventTypeSchema.safeParse(type);
|
|
8032
|
+
if (!result.success) {
|
|
8033
|
+
throw new CliUsageError(`--allowed-event-types entries must be one of: ${activeEventTypeSchema.options.join(", ")}.`);
|
|
8034
|
+
}
|
|
8035
|
+
return result.data;
|
|
8036
|
+
});
|
|
8037
|
+
};
|
|
8038
|
+
var parseIsoDateTime = (value, name) => {
|
|
8039
|
+
if (!/^\d{4}-\d\d-\d\dT\d\d:\d\d/.test(value)) {
|
|
8040
|
+
throw new CliUsageError(`--${name} must be an ISO 8601 date-time such as 2026-11-20T18:00:00+08:00.`);
|
|
8041
|
+
}
|
|
8042
|
+
const parsed = new Date(value);
|
|
8043
|
+
if (Number.isNaN(parsed.getTime())) {
|
|
8044
|
+
throw new CliUsageError(`--${name} must be a valid date-time.`);
|
|
8045
|
+
}
|
|
8046
|
+
return parsed;
|
|
8047
|
+
};
|
|
7504
8048
|
var runCommand = async (parsed, runtime, credentialStore, apiBaseUrl, configureAccessToken) => {
|
|
7505
8049
|
const [group, action, subAction] = parsed.positionals;
|
|
7506
8050
|
const cliVersion = getInstalledCliVersion();
|
|
@@ -7602,6 +8146,44 @@ Waiting for approval\u2026
|
|
|
7602
8146
|
}));
|
|
7603
8147
|
return;
|
|
7604
8148
|
}
|
|
8149
|
+
if ((group === "organization" || group === "org") && action === "create" && subAction === undefined) {
|
|
8150
|
+
assertPositionalCount(parsed, 2);
|
|
8151
|
+
assertOnlyFlags(parsed, ["name", "owner-email", "allowed-event-types"]);
|
|
8152
|
+
const allowedEventTypes = getOptionalFlag(parsed, "allowed-event-types");
|
|
8153
|
+
const input = {
|
|
8154
|
+
name: getRequiredFlag(parsed, "name"),
|
|
8155
|
+
ownerEmail: getRequiredFlag(parsed, "owner-email"),
|
|
8156
|
+
...allowedEventTypes === undefined ? {} : { allowedEventTypes: parseEventTypeList(allowedEventTypes) }
|
|
8157
|
+
};
|
|
8158
|
+
await ensureAuthentication();
|
|
8159
|
+
writeSuccess(runtime, await api2.admin.organization.createOrganization.mutate(input));
|
|
8160
|
+
return;
|
|
8161
|
+
}
|
|
8162
|
+
if (group === "event" && action === "create" && subAction === undefined) {
|
|
8163
|
+
assertPositionalCount(parsed, 2);
|
|
8164
|
+
assertOnlyFlags(parsed, [
|
|
8165
|
+
"organization-id",
|
|
8166
|
+
"name",
|
|
8167
|
+
"type",
|
|
8168
|
+
"start",
|
|
8169
|
+
"end",
|
|
8170
|
+
"location"
|
|
8171
|
+
]);
|
|
8172
|
+
const end = getOptionalFlag(parsed, "end");
|
|
8173
|
+
const input = {
|
|
8174
|
+
organizationId: getRequiredFlag(parsed, "organization-id"),
|
|
8175
|
+
name: getRequiredFlag(parsed, "name"),
|
|
8176
|
+
type: parseCreatableEventType(getRequiredFlag(parsed, "type")),
|
|
8177
|
+
location: getRequiredFlag(parsed, "location"),
|
|
8178
|
+
eventDateRange: {
|
|
8179
|
+
from: parseIsoDateTime(getRequiredFlag(parsed, "start"), "start"),
|
|
8180
|
+
...end === undefined ? {} : { to: parseIsoDateTime(end, "end") }
|
|
8181
|
+
}
|
|
8182
|
+
};
|
|
8183
|
+
await ensureAuthentication();
|
|
8184
|
+
writeSuccess(runtime, await api2.event.createEvent.mutate(input));
|
|
8185
|
+
return;
|
|
8186
|
+
}
|
|
7605
8187
|
if (group === "event" && action === "list" && subAction === undefined) {
|
|
7606
8188
|
assertPositionalCount(parsed, 2);
|
|
7607
8189
|
assertOnlyFlags(parsed, [
|
|
@@ -7679,11 +8261,11 @@ Waiting for approval\u2026
|
|
|
7679
8261
|
const filePath = getRequiredFlag(parsed, "file");
|
|
7680
8262
|
const contentType = getRequiredFlag(parsed, "content-type");
|
|
7681
8263
|
const mediaType = parseAppearanceMediaType(getRequiredFlag(parsed, "media-type"));
|
|
7682
|
-
const file = await
|
|
8264
|
+
const file = await readFile4(filePath);
|
|
7683
8265
|
await ensureAuthentication();
|
|
7684
8266
|
const signed = await api2.attachment.getPresignedUrlToUpload.mutate({
|
|
7685
8267
|
folder: `event-appearance/${mediaType === "image" ? "images" : "videos"}`,
|
|
7686
|
-
fileName:
|
|
8268
|
+
fileName: basename2(filePath),
|
|
7687
8269
|
contentType,
|
|
7688
8270
|
size: file.byteLength,
|
|
7689
8271
|
eventId
|
|
@@ -7714,6 +8296,13 @@ Waiting for approval\u2026
|
|
|
7714
8296
|
writeSuccess(runtime, await api2.event.photoWall.getPhotoWallDisplayItems.query(input));
|
|
7715
8297
|
return;
|
|
7716
8298
|
}
|
|
8299
|
+
if (group === "lucky-draw" && await runLuckyDrawSetupCommand({
|
|
8300
|
+
parsed,
|
|
8301
|
+
runtime,
|
|
8302
|
+
authenticate: ensureAuthentication
|
|
8303
|
+
})) {
|
|
8304
|
+
return;
|
|
8305
|
+
}
|
|
7717
8306
|
if (group === "lucky-draw" && action === "pre-draw" && subAction === undefined) {
|
|
7718
8307
|
assertPositionalCount(parsed, 2);
|
|
7719
8308
|
assertOnlyFlags(parsed, ["event-id", "prize-count"]);
|
|
@@ -7734,21 +8323,11 @@ Waiting for approval\u2026
|
|
|
7734
8323
|
"allow-state-change",
|
|
7735
8324
|
"target"
|
|
7736
8325
|
]);
|
|
7737
|
-
if (parsed.flags.get("allow-state-change") !== true) {
|
|
7738
|
-
throw new CliUsageError("--allow-state-change is required as an explicit acknowledgement.");
|
|
7739
|
-
}
|
|
7740
8326
|
const eventId = getRequiredFlag(parsed, "event-id");
|
|
7741
|
-
|
|
7742
|
-
throw new CliUsageError("--target must exactly match --event-id.");
|
|
7743
|
-
}
|
|
7744
|
-
const participantsValue = getOptionalFlag(parsed, "participants");
|
|
7745
|
-
const participantsFile = getOptionalFlag(parsed, "participants-file");
|
|
7746
|
-
if (participantsValue === undefined === (participantsFile === undefined)) {
|
|
7747
|
-
throw new CliUsageError("Provide exactly one of --participants or --participants-file.");
|
|
7748
|
-
}
|
|
8327
|
+
assertStateChangeTarget(parsed, eventId);
|
|
7749
8328
|
const input = {
|
|
7750
8329
|
eventId,
|
|
7751
|
-
participants: parseLuckyDrawParticipants(
|
|
8330
|
+
participants: parseLuckyDrawParticipants(await readInlineOrFile(parsed, "participants", "participants-file"))
|
|
7752
8331
|
};
|
|
7753
8332
|
await ensureAuthentication();
|
|
7754
8333
|
writeSuccess(runtime, await api2.event.luckyDraw.createLuckyDrawParticipant.mutate(input));
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@go-labs-sg/event-tech",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.4.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.
|
|
20
|
+
"dotenv": "^18.0.9",
|
|
21
21
|
"superjson": "^2.2.6"
|
|
22
22
|
},
|
|
23
23
|
"engines": {
|