Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion docs/assets.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ files:
- imports/server/lookupUrl.ts
- imports/server/models/Blobs.ts
- imports/server/publications/blobMappingsAll.ts
updated: 2026-02-20
updated: 2026-02-21
---

# Custom Asset Pipeline
Expand Down
2 changes: 1 addition & 1 deletion docs/google-drive.md
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ files:
- imports/server/setup.ts
- private/google-script/cookie-test.html
- private/google-script/main.js
updated: 2026-04-14T07:38:00Z
updated: 2026-04-30T00:00:00Z
---

# Google Drive Integration
Expand Down
2 changes: 1 addition & 1 deletion imports/lib/jobs/discordSyncRole.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { z } from "zod";
import { foreignKey } from "../models/customTypes";
import { foreignKey } from "../typedModel/customTypes";
import TypedJob from "./TypedJob";

const discordSyncRole = new TypedJob("discord.syncRole", {
Expand Down
2 changes: 1 addition & 1 deletion imports/lib/jobs/mergeUsers.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { z } from "zod";
import { foreignKey } from "../models/customTypes";
import { foreignKey } from "../typedModel/customTypes";
import TypedJob from "./TypedJob";

const mergeUsers = new TypedJob("user.mergeUsers", {
Expand Down
2 changes: 1 addition & 1 deletion imports/lib/jobs/purgeHunt.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { z } from "zod";
import { foreignKey } from "../models/customTypes";
import { foreignKey } from "../typedModel/customTypes";
import TypedJob from "./TypedJob";

const purgeHunt = new TypedJob("hunt.purgeHunt", {
Expand Down
8 changes: 4 additions & 4 deletions imports/lib/models/APIKeys.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
import { z } from "zod";
import { foreignKey } from "./customTypes";
import type { ModelType } from "./Model";
import SoftDeletedModel from "./SoftDeletedModel";
import withCommon from "./withCommon";
import { foreignKey } from "../typedModel/customTypes";
import type { ModelType } from "../typedModel/Model";
import SoftDeletedModel from "../typedModel/SoftDeletedModel";
import withCommon from "../typedModel/withCommon";

const APIKey = withCommon(
z.object({
Expand Down
8 changes: 4 additions & 4 deletions imports/lib/models/Announcements.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
import { z } from "zod";
import { foreignKey, nonEmptyString } from "./customTypes";
import type { ModelType } from "./Model";
import SoftDeletedModel from "./SoftDeletedModel";
import withCommon from "./withCommon";
import { foreignKey, nonEmptyString } from "../typedModel/customTypes";
import type { ModelType } from "../typedModel/Model";
import SoftDeletedModel from "../typedModel/SoftDeletedModel";
import withCommon from "../typedModel/withCommon";

// A broadcast message from a hunt operator to be displayed
// to all participants in the specified hunt.
Expand Down
6 changes: 3 additions & 3 deletions imports/lib/models/BlobMappings.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { z } from "zod";
import { nonEmptyString } from "./customTypes";
import type { ModelType } from "./Model";
import Model from "./Model";
import { nonEmptyString } from "../typedModel/customTypes";
import type { ModelType } from "../typedModel/Model";
import Model from "../typedModel/Model";

// Note that the _id is the asset name
const BlobMapping = z.object({
Expand Down
8 changes: 4 additions & 4 deletions imports/lib/models/BookmarkNotifications.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
import { z } from "zod";
import type { Solvedness } from "../solvedness";
import { answer, foreignKey } from "./customTypes";
import type { ModelType } from "./Model";
import SoftDeletedModel from "./SoftDeletedModel";
import withCommon from "./withCommon";
import { answer, foreignKey } from "../typedModel/customTypes";
import type { ModelType } from "../typedModel/Model";
import SoftDeletedModel from "../typedModel/SoftDeletedModel";
import withCommon from "../typedModel/withCommon";

const BookmarkNotificationSolvedness: z.ZodType<Solvedness> = z.enum([
"noAnswers",
Expand Down
8 changes: 4 additions & 4 deletions imports/lib/models/Bookmarks.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
import { z } from "zod";
import { foreignKey } from "./customTypes";
import type { ModelType } from "./Model";
import SoftDeletedModel from "./SoftDeletedModel";
import withCommon from "./withCommon";
import { foreignKey } from "../typedModel/customTypes";
import type { ModelType } from "../typedModel/Model";
import SoftDeletedModel from "../typedModel/SoftDeletedModel";
import withCommon from "../typedModel/withCommon";

// Broadcast announcements that have not yet been viewed by a given
// user
Expand Down
11 changes: 6 additions & 5 deletions imports/lib/models/ChatMessages.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
import { z } from "zod";
import { allowedEmptyString, foreignKey } from "./customTypes";
import type { ModelType } from "./Model";
import SoftDeletedModel from "./SoftDeletedModel";
import withCommon from "./withCommon";
import { allowedEmptyString, foreignKey } from "../typedModel/customTypes";
import type { ModelType } from "../typedModel/Model";
import { Url } from "../typedModel/regexes";
import SoftDeletedModel from "../typedModel/SoftDeletedModel";
import withCommon from "../typedModel/withCommon";

const UserMentionBlock = z.object({
type: z.literal("mention"),
Expand All @@ -18,7 +19,7 @@ export type ChatMessageRoleMentionNodeType = z.infer<typeof RoleMentionBlock>;

const ImageBlock = z.object({
type: z.literal("image"),
url: z.string().url(),
url: z.string().regex(Url),
});
export type ChatMessageImageNodeType = z.infer<typeof ImageBlock>;

Expand Down
8 changes: 4 additions & 4 deletions imports/lib/models/ChatNotifications.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
import { z } from "zod";
import { foreignKey } from "../typedModel/customTypes";
import type { ModelType } from "../typedModel/Model";
import SoftDeletedModel from "../typedModel/SoftDeletedModel";
import withCommon from "../typedModel/withCommon";
import { ChatMessageContent } from "./ChatMessages";
import { foreignKey } from "./customTypes";
import type { ModelType } from "./Model";
import SoftDeletedModel from "./SoftDeletedModel";
import withCommon from "./withCommon";

// A notification triggered by a chat message sent by a user.
const ChatNotification = withCommon(
Expand Down
2 changes: 1 addition & 1 deletion imports/lib/models/DiscordAccount.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { z } from "zod";
import { nonEmptyString } from "./customTypes";
import { nonEmptyString } from "../typedModel/customTypes";

const DiscordAccount = z.object({
id: nonEmptyString,
Expand Down
8 changes: 4 additions & 4 deletions imports/lib/models/DiscordCache.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
import { z } from "zod";
import { nonEmptyString, snowflake } from "./customTypes";
import type { ModelType } from "./Model";
import Model from "./Model";
import withTimestamps from "./withTimestamps";
import { nonEmptyString, snowflake } from "../typedModel/customTypes";
import type { ModelType } from "../typedModel/Model";
import Model from "../typedModel/Model";
import withTimestamps from "../typedModel/withTimestamps";

export const DiscordCacheSchema = withTimestamps(
z.object({
Expand Down
8 changes: 4 additions & 4 deletions imports/lib/models/DiscordRoleGrants.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
import { z } from "zod";
import { foreignKey, snowflake } from "./customTypes";
import type { ModelType } from "./Model";
import SoftDeletedModel from "./SoftDeletedModel";
import withCommon from "./withCommon";
import { foreignKey, snowflake } from "../typedModel/customTypes";
import type { ModelType } from "../typedModel/Model";
import SoftDeletedModel from "../typedModel/SoftDeletedModel";
import withCommon from "../typedModel/withCommon";

const DiscordRoleGrant = withCommon(
z.object({
Expand Down
6 changes: 3 additions & 3 deletions imports/lib/models/DocumentActivities.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { z } from "zod";
import { foreignKey } from "./customTypes";
import type { ModelType } from "./Model";
import Model from "./Model";
import { foreignKey } from "../typedModel/customTypes";
import type { ModelType } from "../typedModel/Model";
import Model from "../typedModel/Model";

/* DocumentActivityFields doesn't inherit from Base because it's created by the
server, not by users */
Expand Down
8 changes: 4 additions & 4 deletions imports/lib/models/Documents.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
import { z } from "zod";
import { foreignKey, nonEmptyString } from "./customTypes";
import type { ModelType } from "./Model";
import SoftDeletedModel from "./SoftDeletedModel";
import withCommon from "./withCommon";
import { foreignKey, nonEmptyString } from "../typedModel/customTypes";
import type { ModelType } from "../typedModel/Model";
import SoftDeletedModel from "../typedModel/SoftDeletedModel";
import withCommon from "../typedModel/withCommon";

const DocumentSchema = withCommon(
z
Expand Down
6 changes: 3 additions & 3 deletions imports/lib/models/FeatureFlags.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { z } from "zod";
import type { ModelType } from "./Model";
import SoftDeletedModel from "./SoftDeletedModel";
import withCommon from "./withCommon";
import type { ModelType } from "../typedModel/Model";
import SoftDeletedModel from "../typedModel/SoftDeletedModel";
import withCommon from "../typedModel/withCommon";

export const FlagNames = [
"disable.dingwords",
Expand Down
10 changes: 5 additions & 5 deletions imports/lib/models/FolderPermissions.ts
Original file line number Diff line number Diff line change
@@ -1,15 +1,15 @@
import { z } from "zod";
import { foreignKey, nonEmptyString } from "./customTypes";
import type { ModelType } from "./Model";
import SoftDeletedModel from "./SoftDeletedModel";
import withCommon from "./withCommon";
import { foreignKey, nonEmptyString } from "../typedModel/customTypes";
import type { ModelType } from "../typedModel/Model";
import SoftDeletedModel from "../typedModel/SoftDeletedModel";
import withCommon from "../typedModel/withCommon";

const FolderPermission = withCommon(
z.object({
folder: nonEmptyString,
user: foreignKey,
// This can change, so capture which one we gave permissions to
googleAccount: z.string().email(),
googleAccount: z.email(),
// This is largely a legacy field, as we expect all new grants to use the
// "commenter" permission (which results in correct attribution of Drive
// activity), but we originally granted the "reader" permission instead
Expand Down
12 changes: 6 additions & 6 deletions imports/lib/models/Guesses.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
import { z } from "zod";
import { answer, foreignKey, nonEmptyString } from "./customTypes";
import type { ModelType } from "./Model";
import SoftDeletedModel from "./SoftDeletedModel";
import withCommon from "./withCommon";
import { answer, foreignKey, nonEmptyString } from "../typedModel/customTypes";
import type { ModelType } from "../typedModel/Model";
import SoftDeletedModel from "../typedModel/SoftDeletedModel";
import withCommon from "../typedModel/withCommon";

// The state of this guess, as handled by the operators:
// * 'pending' means "shows up in the operator queue"
Expand Down Expand Up @@ -30,10 +30,10 @@ const Guess = withCommon(
guess: answer,
// Whether this was forward solved (10), backwards solved (-10), or somewhere
// in between (only optional in that older hunts won't have it)
direction: z.number().int().min(-10).max(10).optional(),
direction: z.int32().min(-10).max(10).optional(),
// Submitted-evaluated probability that the answer is right (also only
// optional on older hunts)
confidence: z.number().int().min(0).max(100).optional(),
confidence: z.int32().min(0).max(100).optional(),
state: GuessStates,
// Additional notes can be used by the operator either for sharing (e.g.)
// additional information received from the puzzle (e.g. for an intermediate
Expand Down
11 changes: 6 additions & 5 deletions imports/lib/models/Hunts.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
import { Match } from "meteor/check";
import { z } from "zod";
import { nonEmptyString, snowflake } from "./customTypes";
import type { ModelType } from "./Model";
import SoftDeletedModel from "./SoftDeletedModel";
import withCommon from "./withCommon";
import { nonEmptyString, snowflake } from "../typedModel/customTypes";
import type { ModelType } from "../typedModel/Model";
import { Url } from "../typedModel/regexes";
import SoftDeletedModel from "../typedModel/SoftDeletedModel";
import withCommon from "../typedModel/withCommon";

export const SavedDiscordObjectFields = z.object({
id: snowflake,
Expand Down Expand Up @@ -36,7 +37,7 @@ const EditableHunt = z.object({
submitTemplate: nonEmptyString.optional(),
// If provided, then this is a link to the overall root hunt homepage and will
// be shown in the PuzzleListPage navbar.
homepageUrl: nonEmptyString.url().optional(),
homepageUrl: z.string().regex(Url).optional(),
// If provided, then announcements will be synced to this Discord channel
announcementDiscordChannel: SavedDiscordObjectFields.optional(),
// If provided, this is an object containing a Discord channel id and cached
Expand Down
8 changes: 4 additions & 4 deletions imports/lib/models/InvitationCodes.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
import { z } from "zod";
import { foreignKey, nonEmptyString } from "./customTypes";
import type { ModelType } from "./Model";
import SoftDeletedModel from "./SoftDeletedModel";
import withCommon from "./withCommon";
import { foreignKey, nonEmptyString } from "../typedModel/customTypes";
import type { ModelType } from "../typedModel/Model";
import SoftDeletedModel from "../typedModel/SoftDeletedModel";
import withCommon from "../typedModel/withCommon";

// Invitation codes that can be used to join a hunt.
// These take the place of direct (user-to-user) invitations.
Expand Down
14 changes: 9 additions & 5 deletions imports/lib/models/Jobs.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,11 @@
import { z } from "zod";
import { createdTimestamp, foreignKey, nonEmptyString } from "./customTypes";
import type { ModelType } from "./Model";
import Model from "./Model";
import {
createdTimestamp,
foreignKey,
nonEmptyString,
} from "../typedModel/customTypes";
import type { ModelType } from "../typedModel/Model";
import Model from "../typedModel/Model";

const Job = z.object({
type: nonEmptyString,
Expand All @@ -12,8 +16,8 @@ const Job = z.object({
completedAt: z.date().optional(),
result: z.record(z.string(), z.unknown()).optional(),
error: nonEmptyString.optional(),
attempts: z.number().int().nonnegative().default(0),
maxAttempts: z.number().int().positive(),
attempts: z.int32().nonnegative().default(0),
maxAttempts: z.int32().positive(),
runAfter: z.date().optional(),
deleteAfter: z.date().optional(),
createdBy: foreignKey.optional(),
Expand Down
8 changes: 4 additions & 4 deletions imports/lib/models/MergeOperations.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
import { z } from "zod";
import { foreignKey, nonEmptyString } from "./customTypes";
import { foreignKey, nonEmptyString } from "../typedModel/customTypes";
import type { ModelType } from "../typedModel/Model";
import Model from "../typedModel/Model";
import withCommon from "../typedModel/withCommon";
import DiscordAccount from "./DiscordAccount";
import type { ModelType } from "./Model";
import Model from "./Model";
import withCommon from "./withCommon";

// Audit trail for user merge operations. Each record tracks a merge of
// participants[0] (source, going away) into participants[1] (target,
Expand Down
Loading
Loading