founder-schema 0.16.0 → 0.18.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 +263 -19
- package/dist/access/access.d.ts +1 -1
- package/dist/access/access.d.ts.map +1 -1
- package/dist/access/access.js +4 -1
- package/dist/access/access.js.map +1 -1
- package/dist/access/permissions.d.ts +27 -29
- package/dist/access/permissions.d.ts.map +1 -1
- package/dist/access/permissions.js +39 -3
- package/dist/access/permissions.js.map +1 -1
- package/dist/core/common.d.ts +117 -23
- package/dist/core/common.d.ts.map +1 -1
- package/dist/core/common.js +104 -21
- package/dist/core/common.js.map +1 -1
- package/dist/core/errors.d.ts +7 -5
- package/dist/core/errors.d.ts.map +1 -1
- package/dist/core/errors.js +17 -11
- package/dist/core/errors.js.map +1 -1
- package/dist/core/limits.d.ts +55 -17
- package/dist/core/limits.d.ts.map +1 -1
- package/dist/core/limits.js +59 -22
- package/dist/core/limits.js.map +1 -1
- package/dist/core/money.d.ts +33 -0
- package/dist/core/money.d.ts.map +1 -0
- package/dist/core/money.js +36 -0
- package/dist/core/money.js.map +1 -0
- package/dist/core/responses.d.ts +14 -4
- package/dist/core/responses.d.ts.map +1 -1
- package/dist/core/responses.js.map +1 -1
- package/dist/core/validation.d.ts +32 -2
- package/dist/core/validation.d.ts.map +1 -1
- package/dist/core/validation.js +32 -2
- package/dist/core/validation.js.map +1 -1
- package/dist/domains/billing/billing.d.ts +61 -8
- package/dist/domains/billing/billing.d.ts.map +1 -1
- package/dist/domains/billing/billing.js +58 -22
- package/dist/domains/billing/billing.js.map +1 -1
- package/dist/domains/billing/gst.d.ts.map +1 -1
- package/dist/domains/billing/gst.js +4 -3
- package/dist/domains/billing/gst.js.map +1 -1
- package/dist/domains/chat/chat.d.ts +0 -21
- package/dist/domains/chat/chat.d.ts.map +1 -1
- package/dist/domains/chat/chat.js +0 -20
- package/dist/domains/chat/chat.js.map +1 -1
- package/dist/domains/communities/communities.d.ts +30 -12
- package/dist/domains/communities/communities.d.ts.map +1 -1
- package/dist/domains/communities/communities.js +43 -15
- package/dist/domains/communities/communities.js.map +1 -1
- package/dist/domains/contributions/contributions.d.ts +1 -1
- package/dist/domains/contributions/contributions.js +1 -1
- package/dist/domains/contributions/contributions.js.map +1 -1
- package/dist/domains/dashboard/dashboard.d.ts +3 -1
- package/dist/domains/dashboard/dashboard.d.ts.map +1 -1
- package/dist/domains/dashboard/dashboard.js +23 -7
- package/dist/domains/dashboard/dashboard.js.map +1 -1
- package/dist/domains/discover/discover.d.ts +8 -8
- package/dist/domains/feed/feed.d.ts +55 -153
- package/dist/domains/feed/feed.d.ts.map +1 -1
- package/dist/domains/feed/feed.js +53 -58
- package/dist/domains/feed/feed.js.map +1 -1
- package/dist/domains/location/india.d.ts +215 -0
- package/dist/domains/location/india.d.ts.map +1 -0
- package/dist/domains/location/india.js +1203 -0
- package/dist/domains/location/india.js.map +1 -0
- package/dist/domains/members/members.d.ts +2 -2
- package/dist/domains/membership/membership.d.ts +26 -0
- package/dist/domains/membership/membership.d.ts.map +1 -1
- package/dist/domains/membership/membership.js +55 -1
- package/dist/domains/membership/membership.js.map +1 -1
- package/dist/domains/moderation/moderation.d.ts +2 -2
- package/dist/domains/moderation/moderation.js +3 -3
- package/dist/domains/moderation/moderation.js.map +1 -1
- package/dist/domains/notifications/notifications.d.ts +1 -10
- package/dist/domains/notifications/notifications.d.ts.map +1 -1
- package/dist/domains/notifications/notifications.js +2 -3
- package/dist/domains/notifications/notifications.js.map +1 -1
- package/dist/domains/onboarding/onboarding-answers.d.ts +112 -0
- package/dist/domains/onboarding/onboarding-answers.d.ts.map +1 -0
- package/dist/domains/onboarding/onboarding-answers.js +164 -0
- package/dist/domains/onboarding/onboarding-answers.js.map +1 -0
- package/dist/domains/onboarding/onboarding.d.ts +398 -62
- package/dist/domains/onboarding/onboarding.d.ts.map +1 -1
- package/dist/domains/onboarding/onboarding.js +229 -68
- package/dist/domains/onboarding/onboarding.js.map +1 -1
- package/dist/domains/products/products.d.ts +43 -8
- package/dist/domains/products/products.d.ts.map +1 -1
- package/dist/domains/products/products.js +57 -11
- package/dist/domains/products/products.js.map +1 -1
- package/dist/domains/profile/founder-profile.d.ts +120 -68
- package/dist/domains/profile/founder-profile.d.ts.map +1 -1
- package/dist/domains/profile/founder-profile.js +80 -29
- package/dist/domains/profile/founder-profile.js.map +1 -1
- package/dist/domains/profile/my-profile.d.ts +3 -3
- package/dist/domains/reviews/reviews.d.ts +1 -1
- package/dist/domains/reviews/reviews.d.ts.map +1 -1
- package/dist/domains/reviews/reviews.js +2 -2
- package/dist/domains/reviews/reviews.js.map +1 -1
- package/dist/domains/support/support.d.ts +22 -3
- package/dist/domains/support/support.d.ts.map +1 -1
- package/dist/domains/support/support.js +19 -5
- package/dist/domains/support/support.js.map +1 -1
- package/dist/domains/team/team.d.ts.map +1 -1
- package/dist/domains/team/team.js +3 -6
- package/dist/domains/team/team.js.map +1 -1
- package/dist/domains/uploads/uploads.d.ts +7 -22
- package/dist/domains/uploads/uploads.d.ts.map +1 -1
- package/dist/domains/uploads/uploads.js +7 -21
- package/dist/domains/uploads/uploads.js.map +1 -1
- package/dist/env.d.ts +26 -13
- package/dist/env.d.ts.map +1 -1
- package/dist/env.js +58 -23
- package/dist/env.js.map +1 -1
- package/dist/index.d.ts +18 -15
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +19 -14
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"gst.js","sourceRoot":"","sources":["../../../src/domains/billing/gst.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AACxB,OAAO,
|
|
1
|
+
{"version":3,"file":"gst.js","sourceRoot":"","sources":["../../../src/domains/billing/gst.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * founder-schema: GST, the states and the GSTIN (0.12.0)\n *\n * Its own module so both the billing contract and a member's membership\n * (the billing details they last used, to prefill a checkout) can use it\n * without importing each other.\n *\n * @module founder-schema/domains/billing/gst\n */\n\nimport { z } from 'zod';\nimport {\n BILLING_ADDRESS_MAX,\n BILLING_ADDRESS_MIN,\n BILLING_NAME_MAX,\n BILLING_NAME_MIN,\n GSTIN_LENGTH,\n} from '../../core/limits.js';\nimport { VALIDATION_MESSAGE } from '../../core/validation.js';\n\n// ─── GST: states and the GSTIN ───────────────────────────────────────────────\n\n/**\n * India's states and union territories by their GST state code, the first\n * two digits of every GSTIN registered there. The current codes only: 25\n * (Daman and Diu) merged into 26 in 2020, and 28 (undivided Andhra Pradesh)\n * gave way to 37.\n */\nexport const GST_STATES = [\n { code: '01', name: 'Jammu and Kashmir' },\n { code: '02', name: 'Himachal Pradesh' },\n { code: '03', name: 'Punjab' },\n { code: '04', name: 'Chandigarh' },\n { code: '05', name: 'Uttarakhand' },\n { code: '06', name: 'Haryana' },\n { code: '07', name: 'Delhi' },\n { code: '08', name: 'Rajasthan' },\n { code: '09', name: 'Uttar Pradesh' },\n { code: '10', name: 'Bihar' },\n { code: '11', name: 'Sikkim' },\n { code: '12', name: 'Arunachal Pradesh' },\n { code: '13', name: 'Nagaland' },\n { code: '14', name: 'Manipur' },\n { code: '15', name: 'Mizoram' },\n { code: '16', name: 'Tripura' },\n { code: '17', name: 'Meghalaya' },\n { code: '18', name: 'Assam' },\n { code: '19', name: 'West Bengal' },\n { code: '20', name: 'Jharkhand' },\n { code: '21', name: 'Odisha' },\n { code: '22', name: 'Chhattisgarh' },\n { code: '23', name: 'Madhya Pradesh' },\n { code: '24', name: 'Gujarat' },\n { code: '26', name: 'Dadra and Nagar Haveli and Daman and Diu' },\n { code: '27', name: 'Maharashtra' },\n { code: '29', name: 'Karnataka' },\n { code: '30', name: 'Goa' },\n { code: '31', name: 'Lakshadweep' },\n { code: '32', name: 'Kerala' },\n { code: '33', name: 'Tamil Nadu' },\n { code: '34', name: 'Puducherry' },\n { code: '35', name: 'Andaman and Nicobar Islands' },\n { code: '36', name: 'Telangana' },\n { code: '37', name: 'Andhra Pradesh' },\n { code: '38', name: 'Ladakh' },\n] as const;\nexport type GstStateCode = (typeof GST_STATES)[number]['code'];\nexport const GST_STATE_CODE_VALUES = GST_STATES.map((s) => s.code) as [\n GstStateCode,\n ...GstStateCode[],\n];\nexport const gstStateCodeSchema = z.enum(GST_STATE_CODE_VALUES);\n\n/** The state's name for its code, as an invoice prints it. */\nexport function gstStateName(code: GstStateCode): string {\n return GST_STATES.find((s) => s.code === code)?.name ?? code;\n}\n\n/** GST is 18% on these services, inside every price. */\nexport const GST_RATE_PERCENT = 18;\n\nconst GSTIN_CHARS = '0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ';\nconst GSTIN_PATTERN = /^\\d{2}[A-Z]{5}\\d{4}[A-Z][1-9A-Z]Z[0-9A-Z]$/;\n\n/**\n * Whether a GSTIN's 15th character is the check character of the first 14\n * (the GSTN's base-36 Luhn variant). Catches a mistyped digit, which the\n * pattern alone does not: a B2B invoice with a wrong GSTIN costs the buyer\n * their input credit.\n */\nexport function gstinChecksumValid(gstin: string): boolean {\n if (!GSTIN_PATTERN.test(gstin)) return false;\n let sum = 0;\n for (let i = 0; i < 14; i++) {\n const value = GSTIN_CHARS.indexOf(gstin.charAt(i));\n const product = value * (i % 2 === 0 ? 1 : 2);\n sum += Math.floor(product / 36) + (product % 36);\n }\n const check = (36 - (sum % 36)) % 36;\n return gstin.charAt(14) === GSTIN_CHARS.charAt(check);\n}\n\n/** A GSTIN, upper-cased, pattern AND check character. */\nexport const gstinSchema = z\n .string()\n .trim()\n .max(GSTIN_LENGTH, VALIDATION_MESSAGE.gstinInvalid)\n .transform((v) => v.toUpperCase())\n .refine(gstinChecksumValid, { error: VALIDATION_MESSAGE.gstinInvalid });\n\n/**\n * Who is buying, for the invoice. The state is the place of supply and\n * decides the tax. With a GSTIN (a business claiming input credit) the\n * invoice is B2B: it must carry the buyer's legal name and address, and the\n * state is the GSTIN's own.\n */\nexport const billingDetailsSchema = z\n .object({\n stateCode: gstStateCodeSchema,\n gstin: gstinSchema.optional(),\n legalName: z.string().trim().min(BILLING_NAME_MIN).max(BILLING_NAME_MAX).optional(),\n address: z.string().trim().min(BILLING_ADDRESS_MIN).max(BILLING_ADDRESS_MAX).optional(),\n })\n .refine((body) => !body.gstin || body.gstin.slice(0, 2) === body.stateCode, {\n path: ['stateCode'],\n error: VALIDATION_MESSAGE.gstinStateMismatch,\n })\n .refine((body) => !body.gstin || body.legalName !== undefined, {\n path: ['legalName'],\n error: VALIDATION_MESSAGE.gstinNeedsNameAndAddress,\n })\n .refine((body) => !body.gstin || body.address !== undefined, {\n path: ['address'],\n error: VALIDATION_MESSAGE.gstinNeedsNameAndAddress,\n });\nexport type BillingDetails = z.infer<typeof billingDetailsSchema>;\n"]}
|
|
@@ -248,25 +248,4 @@ export declare const chatParticipantsResponseSchema: z.ZodObject<{
|
|
|
248
248
|
}, z.core.$strip>>;
|
|
249
249
|
}, z.core.$strip>;
|
|
250
250
|
export type ChatParticipantsResponse = z.infer<typeof chatParticipantsResponseSchema>;
|
|
251
|
-
/**
|
|
252
|
-
* @deprecated Since 0.2.0: use `openChatBodySchema`, the same shape under the
|
|
253
|
-
* name of the route that takes it.
|
|
254
|
-
*/
|
|
255
|
-
export declare const chatInvitationBodySchema: z.ZodObject<{
|
|
256
|
-
userId: z.ZodPipe<z.ZodString, z.ZodTransform<string, string>>;
|
|
257
|
-
useAllowance: z.ZodOptional<z.ZodBoolean>;
|
|
258
|
-
}, z.core.$strip>;
|
|
259
|
-
/** @deprecated Since 0.2.0: use `OpenChatBody`. */
|
|
260
|
-
export type ChatInvitationBody = OpenChatBody;
|
|
261
|
-
/**
|
|
262
|
-
* @deprecated Since 0.2.0, and it describes nothing that exists. The browser
|
|
263
|
-
* never holds an invitation: `/chat/open` mints and redeems it server to
|
|
264
|
-
* server. The old `/invitation` route that handed one out could never have
|
|
265
|
-
* worked and is gone.
|
|
266
|
-
*/
|
|
267
|
-
export declare const chatInvitationSchema: z.ZodObject<{
|
|
268
|
-
invitationToken: z.ZodString;
|
|
269
|
-
}, z.core.$strip>;
|
|
270
|
-
/** @deprecated Since 0.2.0. */
|
|
271
|
-
export type ChatInvitation = z.infer<typeof chatInvitationSchema>;
|
|
272
251
|
//# sourceMappingURL=chat.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"chat.d.ts","sourceRoot":"","sources":["../../../src/domains/chat/chat.ts"],"names":[],"mappings":"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
|
|
1
|
+
{"version":3,"file":"chat.d.ts","sourceRoot":"","sources":["../../../src/domains/chat/chat.ts"],"names":[],"mappings":"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"}
|
|
@@ -228,24 +228,4 @@ export const chatParticipantSchema = z.object({
|
|
|
228
228
|
export const chatParticipantsResponseSchema = z.object({
|
|
229
229
|
participants: z.record(z.string(), chatParticipantSchema),
|
|
230
230
|
});
|
|
231
|
-
// ─── Deprecated ──────────────────────────────────────────────────────────────
|
|
232
|
-
//
|
|
233
|
-
// Unused by every consumer, and still exported: removing an export trips the
|
|
234
|
-
// publish rule that refuses a release missing anything the live one has, so it
|
|
235
|
-
// is the user's decision, not a side effect. They were meant to go in 0.3.0;
|
|
236
|
-
// that release kept them.
|
|
237
|
-
/**
|
|
238
|
-
* @deprecated Since 0.2.0: use `openChatBodySchema`, the same shape under the
|
|
239
|
-
* name of the route that takes it.
|
|
240
|
-
*/
|
|
241
|
-
export const chatInvitationBodySchema = openChatBodySchema;
|
|
242
|
-
/**
|
|
243
|
-
* @deprecated Since 0.2.0, and it describes nothing that exists. The browser
|
|
244
|
-
* never holds an invitation: `/chat/open` mints and redeems it server to
|
|
245
|
-
* server. The old `/invitation` route that handed one out could never have
|
|
246
|
-
* worked and is gone.
|
|
247
|
-
*/
|
|
248
|
-
export const chatInvitationSchema = z.object({
|
|
249
|
-
invitationToken: z.string().min(1),
|
|
250
|
-
});
|
|
251
231
|
//# sourceMappingURL=chat.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"chat.js","sourceRoot":"","sources":["../../../src/domains/chat/chat.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * founder-schema — Chat: config, auth token, opening a conversation, participants\n *\n * Founder Circle does not run a chat server. It uses the shared one, which\n * serves several products, and that is the whole reason this file is careful:\n * when one server serves many tenants, the failure mode is SILENT. A push once\n * returned success having sent nothing, because the caller held the wrong\n * product's key and nothing in the exchange said which product it was for.\n *\n * So the rule these shapes exist to hold: TENANCY COMES FROM THE CREDENTIAL,\n * never from a request body. The token says which product it is for, the chat\n * server resolves the product from the token and from nothing else, and a\n * Founder Circle token cannot address another product's conversation even when\n * handed a valid-looking id.\n *\n * ⚠️ TEXT ONLY. There is deliberately no `callsEnabled` flag here, and its\n * absence is the feature: the user ruled chat is text only, there is no call\n * code to branch on, and the browser is told to deny camera and microphone\n * outright. A boolean that can never be true is an invitation to turn it on.\n *\n * @module founder-schema/domains/chat\n */\n\nimport { z } from 'zod';\nimport { objectIdSchema, usernameSchema } from '../../core/common.js';\nimport { CHAT_PARTICIPANTS_MAX } from '../../core/limits.js';\n\n/**\n * The product this package speaks for.\n *\n * Typed as a LITERAL on purpose. If the shared chat server ever hands back a\n * config or a token minted for a different product, parsing fails loudly here\n * rather than the client quietly talking to the wrong tenant. That is exactly\n * the class of bug this file exists to prevent, so it should be impossible to\n * carry past the first parse.\n */\nexport const CHAT_PRODUCT_ID = 'founder-circle' as const;\nexport const chatProductIdSchema = z.literal(CHAT_PRODUCT_ID);\nexport type ChatProductId = z.infer<typeof chatProductIdSchema>;\n\n// ─── Config ──────────────────────────────────────────────────────────────────\n\n/**\n * What the client needs before it can open a socket.\n *\n * ⚠️ `enabled` IS MANDATORY AND IS NOT DERIVED FROM `url`. \"Messaging is not\n * switched on yet\" is a first-class state, not a failure: a 404 is the expected\n * answer today, and the client collapses a disabled flag, a null url, a non-2xx\n * and a thrown fetch to the same quiet \"not on yet\" rather than an error. If\n * `enabled` were inferred from a missing url, \"off\" and \"broken\" would be the\n * same wire shape and the inbox could not tell a member which one it was.\n *\n * ⚠️ `userId` is required and is the field nothing works without. The client\n * needs to know WHO THE VIEWER IS to decide which side a bubble sits on, to\n * filter the viewer out of presence and typing, to pick the other participant\n * for a row's name and avatar, and to tell its own optimistic message from one\n * echoed back. Without it every conversation renders as though the viewer were\n * nobody. It was missing from the first sketch of this endpoint.\n */\nexport const chatConfigSchema = z.object({\n enabled: z.boolean(),\n /** Null whenever chat is not switched on. Never a placeholder string. */\n url: z.url().nullable(),\n /** The VIEWER's id, as the chat server knows them. */\n userId: z.string(),\n /** Which product this config is for. See `chatProductIdSchema`. */\n productId: chatProductIdSchema,\n});\nexport type ChatConfig = z.infer<typeof chatConfigSchema>;\n\n// ─── Auth token ──────────────────────────────────────────────────────────────\n\n/**\n * How long before expiry the client re-mints, in seconds.\n *\n * Exported because it is a contract detail and not an implementation one: a\n * token handed over with two seconds left is a socket that authenticates and is\n * closed again immediately, so the minting side needs to know the consuming\n * side will not use the last minute of a token's life.\n */\nexport const CHAT_TOKEN_REFRESH_MARGIN_SECONDS = 60;\n\n/**\n * How often the live socket re-authenticates, in seconds.\n *\n * Auth is an EVENT on the open socket rather than a handshake parameter, so\n * re-authenticating does not drop the connection.\n *\n * ⚠️ THIS MUST STAY BELOW THE REAL TOKEN LIFETIME, by more than the refresh\n * margin. It assumes a 15 minute token. A re-auth interval longer than the\n * lifetime is a socket that dies every quarter of an hour with no explanation,\n * and the symptom appears far from the cause. If the issued lifetime changes,\n * this number moves with it or the two silently disagree.\n */\nexport const CHAT_SOCKET_REAUTH_SECONDS = 10 * 60;\n\n/**\n * A short-lived token for the shared chat server.\n *\n * ⚠️ BOTH TIME FIELDS ARE KEPT, and they are not redundant, because two\n * different parties read them with two different clocks:\n *\n * `expiresAt` an absolute instant, for the SERVER. The chat server holds the\n * authoritative clock and must reject an expired token on its\n * own, whatever any client believes.\n * `expiresIn` a duration in seconds, for the CLIENT. Scheduling a refresh\n * from `receivedAt + expiresIn` uses only the client's own\n * elapsed time, so a device whose absolute clock is wrong still\n * refreshes correctly. Scheduling from `expiresAt` instead means\n * a browser an hour fast treats every fresh token as already\n * expired and re-mints forever.\n *\n * Dropping either one breaks the party that reads it. This is the same reason\n * OAuth carries `expires_in` on the wire while the token itself carries `exp`.\n *\n * ⚠️ AND THE CLIENT IS NOT THE ENFORCER. Its margin is an optimisation to avoid\n * a pointless round trip. A wrong clock, a tab asleep for an hour, or a modified\n * client all defeat anything the client does, so the chat server rejects an\n * expired token on its own.\n */\nexport const chatAuthTokenSchema = z.object({\n token: z.string().min(1),\n /** ISO 8601. Parsed with `Date.parse`, never an epoch number. */\n expiresAt: z.iso.datetime(),\n /** Seconds from issue. See the note above on why both exist. */\n expiresIn: z.number().int().positive(),\n /** The product this token is scoped to. A mismatch must fail loudly. */\n productId: chatProductIdSchema,\n});\nexport type ChatAuthToken = z.infer<typeof chatAuthTokenSchema>;\n\n// ─── Opening a conversation ──────────────────────────────────────────────────\n\n/**\n * `POST /api/v1/chat/open`: start (or find) the direct conversation with\n * another member.\n *\n * Our backend decides who may talk to whom, because only it knows this\n * product's rules, and it does the whole exchange with the chat server itself:\n * it mints the viewer's token and an invitation naming both participants, and\n * redeems them server to server. No credential reaches the browser.\n */\nexport const openChatBodySchema = z.object({\n /** The OTHER participant. The viewer is taken from the credential, never the body. */\n userId: objectIdSchema,\n /**\n * Agreement to use one of this month's allowance (0.12.0), when they do\n * not know the other person. Without it such an open is refused with\n * `MESSAGE_ALLOWANCE_UNCONFIRMED` and nothing is spent: an allowance is\n * never used by accident. Ignored for someone they know.\n */\n useAllowance: z.boolean().optional(),\n});\nexport type OpenChatBody = z.infer<typeof openChatBodySchema>;\n\n/**\n * How a conversation came to be allowed (0.12.0): they know each other, it\n * used the opener's allowance, or the opener was acting as a staff role,\n * which reaches anyone. ⚠ Stored: append only.\n */\nexport const CHAT_OPENED_VIA_VALUES = ['contact', 'allowance', 'staff'] as const;\nexport const chatOpenedViaSchema = z.enum(CHAT_OPENED_VIA_VALUES);\nexport type ChatOpenedVia = z.infer<typeof chatOpenedViaSchema>;\n\n/**\n * The conversation to navigate to. `201` with `wasCreated: true` the first\n * time, `200` and `false` on every later open of the same pair.\n */\nexport const openChatResponseSchema = z.object({\n conversationId: z.string().min(1),\n wasCreated: z.boolean(),\n /** 0.12.0. Every later open of the same pair is `contact`: they have a conversation now. */\n via: chatOpenedViaSchema,\n});\nexport type OpenChatResponse = z.infer<typeof openChatResponseSchema>;\n\n// ─── Who may start a conversation with whom (0.12.0) ─────────────────────────\n\n/**\n * Whether opening a conversation with someone would work, and what it would\n * cost, so the button can say so BEFORE it is tapped\n * (`GET /api/v1/chat/reach/:userId`):\n *\n * contact they know each other: free\n * allowance uses one of `left` new people this month: confirm first\n * allowance_exhausted none left this month (`resetsAt`)\n * plan_required they do not know each other and the asker has no plan\n * membership_required the asker cannot chat at all (a viewer)\n * not_accepted the other person takes conversations only from people\n * they know, or cannot chat (one answer for both)\n * staff the asker acts as a staff role, which starts a\n * conversation with anyone who can chat: free, past\n * their \"people I know only\" (the user, 2026-10-12)\n */\nexport const CHAT_REACH_VALUES = [\n 'contact',\n 'allowance',\n 'allowance_exhausted',\n 'plan_required',\n 'membership_required',\n 'not_accepted',\n 'staff',\n] as const;\nexport const chatReachKindSchema = z.enum(CHAT_REACH_VALUES);\nexport type ChatReachKind = z.infer<typeof chatReachKindSchema>;\n\nexport const chatReachSchema = z.object({\n reach: chatReachKindSchema,\n /** For `allowance`: how many new people are left this month, this one included. */\n left: z.number().int().nonnegative().nullable(),\n /** For `allowance` and `allowance_exhausted`: when the month's count starts again. */\n resetsAt: z.iso.datetime().nullable(),\n});\nexport type ChatReach = z.infer<typeof chatReachSchema>;\n\nexport const chatReachParamsSchema = z.object({ userId: objectIdSchema });\nexport type ChatReachParams = z.infer<typeof chatReachParamsSchema>;\n\n/**\n * Who may start a conversation with me (0.12.0). People I know always may.\n * ⚠ Stored: append only.\n *\n * contacts only people I know\n * contacts_and_plans also Premium and Business members (the default)\n */\nexport const MESSAGE_FROM_VALUES = ['contacts', 'contacts_and_plans'] as const;\nexport const messageFromSchema = z.enum(MESSAGE_FROM_VALUES);\nexport type MessageFrom = z.infer<typeof messageFromSchema>;\n\n/** `GET` and `PUT /api/v1/me/messaging`. */\nexport const messagingSettingsSchema = z.object({ from: messageFromSchema });\nexport type MessagingSettings = z.infer<typeof messagingSettingsSchema>;\n\n// ─── Participants ────────────────────────────────────────────────────────────\n\n/**\n * `POST /api/v1/chat/participants`: names and avatars for the people in the\n * viewer's conversations.\n *\n * The chat server knows ids and nothing about who anybody is, because it serves\n * several products and identity belongs to each; so the conversation list asks\n * here, once per screen. Bounded by `CHAT_PARTICIPANTS_MAX`, so it cannot page\n * through the directory.\n */\nexport const chatParticipantsBodySchema = z.object({\n userIds: z.array(objectIdSchema).min(1).max(CHAT_PARTICIPANTS_MAX),\n});\nexport type ChatParticipantsBody = z.infer<typeof chatParticipantsBodySchema>;\n\n/** The public card fields any member already sees, and nothing more. */\nexport const chatParticipantSchema = z.object({\n displayName: z.string(),\n username: usernameSchema,\n /** Null when the member has no photo. Ours, or from the login provider. */\n avatarUrl: z.url().nullable(),\n});\nexport type ChatParticipant = z.infer<typeof chatParticipantSchema>;\n\n/**\n * Keyed by user id. ⚠ An id with no active, onboarded profile is ABSENT, not\n * an error: the client renders it as a former member rather than guessing.\n */\nexport const chatParticipantsResponseSchema = z.object({\n participants: z.record(z.string(), chatParticipantSchema),\n});\nexport type ChatParticipantsResponse = z.infer<typeof chatParticipantsResponseSchema>;\n\n// ─── Deprecated ──────────────────────────────────────────────────────────────\n//\n// Unused by every consumer, and still exported: removing an export trips the\n// publish rule that refuses a release missing anything the live one has, so it\n// is the user's decision, not a side effect. They were meant to go in 0.3.0;\n// that release kept them.\n\n/**\n * @deprecated Since 0.2.0: use `openChatBodySchema`, the same shape under the\n * name of the route that takes it.\n */\nexport const chatInvitationBodySchema = openChatBodySchema;\n/** @deprecated Since 0.2.0: use `OpenChatBody`. */\nexport type ChatInvitationBody = OpenChatBody;\n\n/**\n * @deprecated Since 0.2.0, and it describes nothing that exists. The browser\n * never holds an invitation: `/chat/open` mints and redeems it server to\n * server. The old `/invitation` route that handed one out could never have\n * worked and is gone.\n */\nexport const chatInvitationSchema = z.object({\n invitationToken: z.string().min(1),\n});\n/** @deprecated Since 0.2.0. */\nexport type ChatInvitation = z.infer<typeof chatInvitationSchema>;\n"]}
|
|
1
|
+
{"version":3,"file":"chat.js","sourceRoot":"","sources":["../../../src/domains/chat/chat.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * founder-schema — Chat: config, auth token, opening a conversation, participants\n *\n * Founder Circle does not run a chat server. It uses the shared one, which\n * serves several products, and that is the whole reason this file is careful:\n * when one server serves many tenants, the failure mode is SILENT. A push once\n * returned success having sent nothing, because the caller held the wrong\n * product's key and nothing in the exchange said which product it was for.\n *\n * So the rule these shapes exist to hold: TENANCY COMES FROM THE CREDENTIAL,\n * never from a request body. The token says which product it is for, the chat\n * server resolves the product from the token and from nothing else, and a\n * Founder Circle token cannot address another product's conversation even when\n * handed a valid-looking id.\n *\n * ⚠️ TEXT ONLY. There is deliberately no `callsEnabled` flag here, and its\n * absence is the feature: the user ruled chat is text only, there is no call\n * code to branch on, and the browser is told to deny camera and microphone\n * outright. A boolean that can never be true is an invitation to turn it on.\n *\n * @module founder-schema/domains/chat\n */\n\nimport { z } from 'zod';\nimport { objectIdSchema, usernameSchema } from '../../core/common.js';\nimport { CHAT_PARTICIPANTS_MAX } from '../../core/limits.js';\n\n/**\n * The product this package speaks for.\n *\n * Typed as a LITERAL on purpose. If the shared chat server ever hands back a\n * config or a token minted for a different product, parsing fails loudly here\n * rather than the client quietly talking to the wrong tenant. That is exactly\n * the class of bug this file exists to prevent, so it should be impossible to\n * carry past the first parse.\n */\nexport const CHAT_PRODUCT_ID = 'founder-circle' as const;\nexport const chatProductIdSchema = z.literal(CHAT_PRODUCT_ID);\nexport type ChatProductId = z.infer<typeof chatProductIdSchema>;\n\n// ─── Config ──────────────────────────────────────────────────────────────────\n\n/**\n * What the client needs before it can open a socket.\n *\n * ⚠️ `enabled` IS MANDATORY AND IS NOT DERIVED FROM `url`. \"Messaging is not\n * switched on yet\" is a first-class state, not a failure: a 404 is the expected\n * answer today, and the client collapses a disabled flag, a null url, a non-2xx\n * and a thrown fetch to the same quiet \"not on yet\" rather than an error. If\n * `enabled` were inferred from a missing url, \"off\" and \"broken\" would be the\n * same wire shape and the inbox could not tell a member which one it was.\n *\n * ⚠️ `userId` is required and is the field nothing works without. The client\n * needs to know WHO THE VIEWER IS to decide which side a bubble sits on, to\n * filter the viewer out of presence and typing, to pick the other participant\n * for a row's name and avatar, and to tell its own optimistic message from one\n * echoed back. Without it every conversation renders as though the viewer were\n * nobody. It was missing from the first sketch of this endpoint.\n */\nexport const chatConfigSchema = z.object({\n enabled: z.boolean(),\n /** Null whenever chat is not switched on. Never a placeholder string. */\n url: z.url().nullable(),\n /** The VIEWER's id, as the chat server knows them. */\n userId: z.string(),\n /** Which product this config is for. See `chatProductIdSchema`. */\n productId: chatProductIdSchema,\n});\nexport type ChatConfig = z.infer<typeof chatConfigSchema>;\n\n// ─── Auth token ──────────────────────────────────────────────────────────────\n\n/**\n * How long before expiry the client re-mints, in seconds.\n *\n * Exported because it is a contract detail and not an implementation one: a\n * token handed over with two seconds left is a socket that authenticates and is\n * closed again immediately, so the minting side needs to know the consuming\n * side will not use the last minute of a token's life.\n */\nexport const CHAT_TOKEN_REFRESH_MARGIN_SECONDS = 60;\n\n/**\n * How often the live socket re-authenticates, in seconds.\n *\n * Auth is an EVENT on the open socket rather than a handshake parameter, so\n * re-authenticating does not drop the connection.\n *\n * ⚠️ THIS MUST STAY BELOW THE REAL TOKEN LIFETIME, by more than the refresh\n * margin. It assumes a 15 minute token. A re-auth interval longer than the\n * lifetime is a socket that dies every quarter of an hour with no explanation,\n * and the symptom appears far from the cause. If the issued lifetime changes,\n * this number moves with it or the two silently disagree.\n */\nexport const CHAT_SOCKET_REAUTH_SECONDS = 10 * 60;\n\n/**\n * A short-lived token for the shared chat server.\n *\n * ⚠️ BOTH TIME FIELDS ARE KEPT, and they are not redundant, because two\n * different parties read them with two different clocks:\n *\n * `expiresAt` an absolute instant, for the SERVER. The chat server holds the\n * authoritative clock and must reject an expired token on its\n * own, whatever any client believes.\n * `expiresIn` a duration in seconds, for the CLIENT. Scheduling a refresh\n * from `receivedAt + expiresIn` uses only the client's own\n * elapsed time, so a device whose absolute clock is wrong still\n * refreshes correctly. Scheduling from `expiresAt` instead means\n * a browser an hour fast treats every fresh token as already\n * expired and re-mints forever.\n *\n * Dropping either one breaks the party that reads it. This is the same reason\n * OAuth carries `expires_in` on the wire while the token itself carries `exp`.\n *\n * ⚠️ AND THE CLIENT IS NOT THE ENFORCER. Its margin is an optimisation to avoid\n * a pointless round trip. A wrong clock, a tab asleep for an hour, or a modified\n * client all defeat anything the client does, so the chat server rejects an\n * expired token on its own.\n */\nexport const chatAuthTokenSchema = z.object({\n token: z.string().min(1),\n /** ISO 8601. Parsed with `Date.parse`, never an epoch number. */\n expiresAt: z.iso.datetime(),\n /** Seconds from issue. See the note above on why both exist. */\n expiresIn: z.number().int().positive(),\n /** The product this token is scoped to. A mismatch must fail loudly. */\n productId: chatProductIdSchema,\n});\nexport type ChatAuthToken = z.infer<typeof chatAuthTokenSchema>;\n\n// ─── Opening a conversation ──────────────────────────────────────────────────\n\n/**\n * `POST /api/v1/chat/open`: start (or find) the direct conversation with\n * another member.\n *\n * Our backend decides who may talk to whom, because only it knows this\n * product's rules, and it does the whole exchange with the chat server itself:\n * it mints the viewer's token and an invitation naming both participants, and\n * redeems them server to server. No credential reaches the browser.\n */\nexport const openChatBodySchema = z.object({\n /** The OTHER participant. The viewer is taken from the credential, never the body. */\n userId: objectIdSchema,\n /**\n * Agreement to use one of this month's allowance (0.12.0), when they do\n * not know the other person. Without it such an open is refused with\n * `MESSAGE_ALLOWANCE_UNCONFIRMED` and nothing is spent: an allowance is\n * never used by accident. Ignored for someone they know.\n */\n useAllowance: z.boolean().optional(),\n});\nexport type OpenChatBody = z.infer<typeof openChatBodySchema>;\n\n/**\n * How a conversation came to be allowed (0.12.0): they know each other, it\n * used the opener's allowance, or the opener was acting as a staff role,\n * which reaches anyone. ⚠ Stored: append only.\n */\nexport const CHAT_OPENED_VIA_VALUES = ['contact', 'allowance', 'staff'] as const;\nexport const chatOpenedViaSchema = z.enum(CHAT_OPENED_VIA_VALUES);\nexport type ChatOpenedVia = z.infer<typeof chatOpenedViaSchema>;\n\n/**\n * The conversation to navigate to. `201` with `wasCreated: true` the first\n * time, `200` and `false` on every later open of the same pair.\n */\nexport const openChatResponseSchema = z.object({\n conversationId: z.string().min(1),\n wasCreated: z.boolean(),\n /** 0.12.0. Every later open of the same pair is `contact`: they have a conversation now. */\n via: chatOpenedViaSchema,\n});\nexport type OpenChatResponse = z.infer<typeof openChatResponseSchema>;\n\n// ─── Who may start a conversation with whom (0.12.0) ─────────────────────────\n\n/**\n * Whether opening a conversation with someone would work, and what it would\n * cost, so the button can say so BEFORE it is tapped\n * (`GET /api/v1/chat/reach/:userId`):\n *\n * contact they know each other: free\n * allowance uses one of `left` new people this month: confirm first\n * allowance_exhausted none left this month (`resetsAt`)\n * plan_required they do not know each other and the asker has no plan\n * membership_required the asker cannot chat at all (a viewer)\n * not_accepted the other person takes conversations only from people\n * they know, or cannot chat (one answer for both)\n * staff the asker acts as a staff role, which starts a\n * conversation with anyone who can chat: free, past\n * their \"people I know only\" (the user, 2026-10-12)\n */\nexport const CHAT_REACH_VALUES = [\n 'contact',\n 'allowance',\n 'allowance_exhausted',\n 'plan_required',\n 'membership_required',\n 'not_accepted',\n 'staff',\n] as const;\nexport const chatReachKindSchema = z.enum(CHAT_REACH_VALUES);\nexport type ChatReachKind = z.infer<typeof chatReachKindSchema>;\n\nexport const chatReachSchema = z.object({\n reach: chatReachKindSchema,\n /** For `allowance`: how many new people are left this month, this one included. */\n left: z.number().int().nonnegative().nullable(),\n /** For `allowance` and `allowance_exhausted`: when the month's count starts again. */\n resetsAt: z.iso.datetime().nullable(),\n});\nexport type ChatReach = z.infer<typeof chatReachSchema>;\n\nexport const chatReachParamsSchema = z.object({ userId: objectIdSchema });\nexport type ChatReachParams = z.infer<typeof chatReachParamsSchema>;\n\n/**\n * Who may start a conversation with me (0.12.0). People I know always may.\n * ⚠ Stored: append only.\n *\n * contacts only people I know\n * contacts_and_plans also Premium and Business members (the default)\n */\nexport const MESSAGE_FROM_VALUES = ['contacts', 'contacts_and_plans'] as const;\nexport const messageFromSchema = z.enum(MESSAGE_FROM_VALUES);\nexport type MessageFrom = z.infer<typeof messageFromSchema>;\n\n/** `GET` and `PUT /api/v1/me/messaging`. */\nexport const messagingSettingsSchema = z.object({ from: messageFromSchema });\nexport type MessagingSettings = z.infer<typeof messagingSettingsSchema>;\n\n// ─── Participants ────────────────────────────────────────────────────────────\n\n/**\n * `POST /api/v1/chat/participants`: names and avatars for the people in the\n * viewer's conversations.\n *\n * The chat server knows ids and nothing about who anybody is, because it serves\n * several products and identity belongs to each; so the conversation list asks\n * here, once per screen. Bounded by `CHAT_PARTICIPANTS_MAX`, so it cannot page\n * through the directory.\n */\nexport const chatParticipantsBodySchema = z.object({\n userIds: z.array(objectIdSchema).min(1).max(CHAT_PARTICIPANTS_MAX),\n});\nexport type ChatParticipantsBody = z.infer<typeof chatParticipantsBodySchema>;\n\n/** The public card fields any member already sees, and nothing more. */\nexport const chatParticipantSchema = z.object({\n displayName: z.string(),\n username: usernameSchema,\n /** Null when the member has no photo. Ours, or from the login provider. */\n avatarUrl: z.url().nullable(),\n});\nexport type ChatParticipant = z.infer<typeof chatParticipantSchema>;\n\n/**\n * Keyed by user id. ⚠ An id with no active, onboarded profile is ABSENT, not\n * an error: the client renders it as a former member rather than guessing.\n */\nexport const chatParticipantsResponseSchema = z.object({\n participants: z.record(z.string(), chatParticipantSchema),\n});\nexport type ChatParticipantsResponse = z.infer<typeof chatParticipantsResponseSchema>;\n"]}
|
|
@@ -16,9 +16,11 @@
|
|
|
16
16
|
* joining one tap request, then invite only,
|
|
17
17
|
* approval then accept
|
|
18
18
|
*
|
|
19
|
-
* Taking part (post, poll, comment, react, vote, save
|
|
20
|
-
*
|
|
21
|
-
*
|
|
19
|
+
* Taking part (post, poll, comment, react, vote, save) is for members of
|
|
20
|
+
* every type. "Members" means ACTIVE members: someone who requested, was
|
|
21
|
+
* invited or is banned is a non-member for every rule. Taking a reaction,
|
|
22
|
+
* a vote or a save BACK needs only read access, and reporting is open to
|
|
23
|
+
* any signed-in reader (safety, 0.13.0).
|
|
22
24
|
* - PUBLIC MEANS PUBLIC INSIDE FOUNDER CIRCLE: a signed-out visitor sees no
|
|
23
25
|
* community content of any type, even by a shared link.
|
|
24
26
|
* - THE HOME FEED adds only the communities the member joined.
|
|
@@ -174,11 +176,25 @@ export declare const communityStatusSchema: z.ZodEnum<{
|
|
|
174
176
|
archived: "archived";
|
|
175
177
|
}>;
|
|
176
178
|
export type CommunityStatus = z.infer<typeof communityStatusSchema>;
|
|
179
|
+
/**
|
|
180
|
+
* Whether a community may take type `to` now (0.18.0): ONE rule for the
|
|
181
|
+
* server's refusal (`COMMUNITY_ARCHIVED`) and the screen's choice. An
|
|
182
|
+
* archived community lets nobody new in, so it may be narrowed (private,
|
|
183
|
+
* hidden) but never opened to public, which would let its waiting requests in.
|
|
184
|
+
*/
|
|
185
|
+
export declare function communityTypeChangeAllowed(status: CommunityStatus, to: CommunityVisibility): boolean;
|
|
186
|
+
/** How staff decided a suggestion (0.18.0: named, for the bell and the backend's model). */
|
|
187
|
+
export declare const COMMUNITY_SUGGESTION_DECISION_VALUES: readonly ["approved", "declined"];
|
|
188
|
+
export declare const communitySuggestionDecisionSchema: z.ZodEnum<{
|
|
189
|
+
approved: "approved";
|
|
190
|
+
declined: "declined";
|
|
191
|
+
}>;
|
|
192
|
+
export type CommunitySuggestionDecision = z.infer<typeof communitySuggestionDecisionSchema>;
|
|
177
193
|
export declare const COMMUNITY_SUGGESTION_STATUS_VALUES: readonly ["open", "approved", "declined"];
|
|
178
194
|
export declare const communitySuggestionStatusSchema: z.ZodEnum<{
|
|
179
|
-
open: "open";
|
|
180
195
|
approved: "approved";
|
|
181
196
|
declined: "declined";
|
|
197
|
+
open: "open";
|
|
182
198
|
}>;
|
|
183
199
|
export type CommunitySuggestionStatus = z.infer<typeof communitySuggestionStatusSchema>;
|
|
184
200
|
/**
|
|
@@ -349,6 +365,7 @@ export declare const communityViewerSchema: z.ZodObject<{
|
|
|
349
365
|
canRequest: z.ZodBoolean;
|
|
350
366
|
canPost: z.ZodBoolean;
|
|
351
367
|
canLeave: z.ZodBoolean;
|
|
368
|
+
leaveArchives: z.ZodBoolean;
|
|
352
369
|
canModerate: z.ZodBoolean;
|
|
353
370
|
canManage: z.ZodBoolean;
|
|
354
371
|
canAssign: z.ZodBoolean;
|
|
@@ -523,6 +540,7 @@ export declare const communitySchema: z.ZodObject<{
|
|
|
523
540
|
canRequest: z.ZodBoolean;
|
|
524
541
|
canPost: z.ZodBoolean;
|
|
525
542
|
canLeave: z.ZodBoolean;
|
|
543
|
+
leaveArchives: z.ZodBoolean;
|
|
526
544
|
canModerate: z.ZodBoolean;
|
|
527
545
|
canManage: z.ZodBoolean;
|
|
528
546
|
canAssign: z.ZodBoolean;
|
|
@@ -725,9 +743,9 @@ export declare const communitySuggestionSchema: z.ZodObject<{
|
|
|
725
743
|
education_access: "education_access";
|
|
726
744
|
}>>;
|
|
727
745
|
status: z.ZodEnum<{
|
|
728
|
-
open: "open";
|
|
729
746
|
approved: "approved";
|
|
730
747
|
declined: "declined";
|
|
748
|
+
open: "open";
|
|
731
749
|
}>;
|
|
732
750
|
decidedBy: z.ZodNullable<z.ZodObject<{
|
|
733
751
|
userId: z.ZodString;
|
|
@@ -1040,9 +1058,9 @@ export declare const communitySuggestionPageSchema: z.ZodObject<{
|
|
|
1040
1058
|
education_access: "education_access";
|
|
1041
1059
|
}>>;
|
|
1042
1060
|
status: z.ZodEnum<{
|
|
1043
|
-
open: "open";
|
|
1044
1061
|
approved: "approved";
|
|
1045
1062
|
declined: "declined";
|
|
1063
|
+
open: "open";
|
|
1046
1064
|
}>;
|
|
1047
1065
|
decidedBy: z.ZodNullable<z.ZodObject<{
|
|
1048
1066
|
userId: z.ZodString;
|
|
@@ -1077,8 +1095,8 @@ export type CommunitySuggestionPage = z.infer<typeof communitySuggestionPageSche
|
|
|
1077
1095
|
*/
|
|
1078
1096
|
export declare const communityDiscoverQuerySchema: z.ZodObject<{
|
|
1079
1097
|
limit: z.ZodPreprocess<z.ZodDefault<z.ZodCoercedNumber<unknown>>, unknown>;
|
|
1080
|
-
cursor: z.ZodOptional<z.ZodString>;
|
|
1081
|
-
q: z.
|
|
1098
|
+
cursor: z.ZodPreprocess<z.ZodOptional<z.ZodString>, unknown>;
|
|
1099
|
+
q: z.ZodOptional<z.ZodPipe<z.ZodString, z.ZodTransform<string | undefined, string>>>;
|
|
1082
1100
|
topic: z.ZodPreprocess<z.ZodOptional<z.ZodArray<z.ZodEnum<{
|
|
1083
1101
|
ai_ml: "ai_ml";
|
|
1084
1102
|
b2b_saas: "b2b_saas";
|
|
@@ -1157,7 +1175,7 @@ export type CommunityDiscoverQueryInput = z.input<typeof communityDiscoverQueryS
|
|
|
1157
1175
|
/** `GET /communities/:id/members`: everyone, or one role (`?role=admin`). */
|
|
1158
1176
|
export declare const communityMembersQuerySchema: z.ZodObject<{
|
|
1159
1177
|
limit: z.ZodPreprocess<z.ZodDefault<z.ZodCoercedNumber<unknown>>, unknown>;
|
|
1160
|
-
cursor: z.ZodOptional<z.ZodString>;
|
|
1178
|
+
cursor: z.ZodPreprocess<z.ZodOptional<z.ZodString>, unknown>;
|
|
1161
1179
|
role: z.ZodPreprocess<z.ZodOptional<z.ZodEnum<{
|
|
1162
1180
|
admin: "admin";
|
|
1163
1181
|
moderator: "moderator";
|
|
@@ -1169,11 +1187,11 @@ export type CommunityMembersQueryInput = z.input<typeof communityMembersQuerySch
|
|
|
1169
1187
|
/** `GET /community-suggestions` (staff): waiting ones by default, oldest first. */
|
|
1170
1188
|
export declare const communitySuggestionsQuerySchema: z.ZodObject<{
|
|
1171
1189
|
limit: z.ZodPreprocess<z.ZodDefault<z.ZodCoercedNumber<unknown>>, unknown>;
|
|
1172
|
-
cursor: z.ZodOptional<z.ZodString>;
|
|
1190
|
+
cursor: z.ZodPreprocess<z.ZodOptional<z.ZodString>, unknown>;
|
|
1173
1191
|
status: z.ZodPreprocess<z.ZodDefault<z.ZodEnum<{
|
|
1174
|
-
open: "open";
|
|
1175
1192
|
approved: "approved";
|
|
1176
1193
|
declined: "declined";
|
|
1194
|
+
open: "open";
|
|
1177
1195
|
}>>, unknown>;
|
|
1178
1196
|
}, z.core.$strip>;
|
|
1179
1197
|
export type CommunitySuggestionsQuery = z.infer<typeof communitySuggestionsQuerySchema>;
|
|
@@ -1427,7 +1445,7 @@ export type SetCommunityMemberRoleBody = z.infer<typeof setCommunityMemberRoleBo
|
|
|
1427
1445
|
/** `POST /communities/:id/bans` (admins): removes them if active, and keeps them out. */
|
|
1428
1446
|
export declare const banCommunityMemberBodySchema: z.ZodObject<{
|
|
1429
1447
|
userId: z.ZodPipe<z.ZodString, z.ZodTransform<string, string>>;
|
|
1430
|
-
reason: z.ZodOptional<z.ZodString
|
|
1448
|
+
reason: z.ZodOptional<z.ZodPipe<z.ZodString, z.ZodTransform<string | undefined, string>>>;
|
|
1431
1449
|
}, z.core.$strip>;
|
|
1432
1450
|
export type BanCommunityMemberBody = z.infer<typeof banCommunityMemberBodySchema>;
|
|
1433
1451
|
/**
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"communities.d.ts","sourceRoot":"","sources":["../../../src/domains/communities/communities.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"communities.d.ts","sourceRoot":"","sources":["../../../src/domains/communities/communities.ts"],"names":[],"mappings":"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"}
|
|
@@ -16,9 +16,11 @@
|
|
|
16
16
|
* joining one tap request, then invite only,
|
|
17
17
|
* approval then accept
|
|
18
18
|
*
|
|
19
|
-
* Taking part (post, poll, comment, react, vote, save
|
|
20
|
-
*
|
|
21
|
-
*
|
|
19
|
+
* Taking part (post, poll, comment, react, vote, save) is for members of
|
|
20
|
+
* every type. "Members" means ACTIVE members: someone who requested, was
|
|
21
|
+
* invited or is banned is a non-member for every rule. Taking a reaction,
|
|
22
|
+
* a vote or a save BACK needs only read access, and reporting is open to
|
|
23
|
+
* any signed-in reader (safety, 0.13.0).
|
|
22
24
|
* - PUBLIC MEANS PUBLIC INSIDE FOUNDER CIRCLE: a signed-out visitor sees no
|
|
23
25
|
* community content of any type, even by a shared link.
|
|
24
26
|
* - THE HOME FEED adds only the communities the member joined.
|
|
@@ -116,8 +118,8 @@
|
|
|
116
118
|
* @module founder-schema/domains/communities
|
|
117
119
|
*/
|
|
118
120
|
import { z } from 'zod';
|
|
119
|
-
import { emptyStringToUndefined, multiValueQuery, objectIdSchema, optionalTrimmedString, paginationQuerySchema, } from '../../core/common.js';
|
|
120
|
-
import { COMMUNITY_BAN_REASON_MAX, COMMUNITY_DECLINE_REASON_MAX, COMMUNITY_DECLINE_REASON_MIN, COMMUNITY_DESCRIPTION_MAX, COMMUNITY_NAME_MAX, COMMUNITY_NAME_MIN, COMMUNITY_RULE_MAX, COMMUNITY_RULES_MAX, COMMUNITY_SUGGESTION_WHY_MAX, DISCOVER_FILTER_VALUES_MAX, DISCOVER_TEXT_MAX, } from '../../core/limits.js';
|
|
121
|
+
import { eachOnce, emptyStringToUndefined, multiValueQuery, objectIdSchema, optionalTrimmedString, paginationQuerySchema, } from '../../core/common.js';
|
|
122
|
+
import { COMMUNITY_BAN_REASON_MAX, COMMUNITY_DECLINE_REASON_MAX, COMMUNITY_DECLINE_REASON_MIN, COMMUNITY_DESCRIPTION_MAX, COMMUNITY_NAME_MAX, COMMUNITY_NAME_MIN, COMMUNITY_RULE_MAX, COMMUNITY_RULES_MAX, COMMUNITY_SUGGESTION_WHY_MAX, DAY_MS, DISCOVER_FILTER_VALUES_MAX, DISCOVER_TEXT_MAX, } from '../../core/limits.js';
|
|
121
123
|
import { paginatedSchema } from '../../core/responses.js';
|
|
122
124
|
import { VALIDATION_MESSAGE } from '../../core/validation.js';
|
|
123
125
|
import { mediaImageSchema } from '../media/media.js';
|
|
@@ -133,7 +135,7 @@ export const COMMUNITY_SUGGESTIONS_OPEN_MAX = 3;
|
|
|
133
135
|
* The shortest time between two notify-everyone announcements in one
|
|
134
136
|
* community, so members are not spammed (`COMMUNITY_ANNOUNCE_TOO_SOON`).
|
|
135
137
|
*/
|
|
136
|
-
export const COMMUNITY_ANNOUNCE_INTERVAL_MS =
|
|
138
|
+
export const COMMUNITY_ANNOUNCE_INTERVAL_MS = DAY_MS;
|
|
137
139
|
// ─── Vocabulary ──────────────────────────────────────────────────────────────
|
|
138
140
|
// ⚠ Every list below is STORED. Append only; removing a value orphans rows.
|
|
139
141
|
/** See the module note's table. */
|
|
@@ -165,7 +167,22 @@ export const communityMemberStatusSchema = z.enum(COMMUNITY_MEMBER_STATUS_VALUES
|
|
|
165
167
|
/** `archived`: read-only and out of Discover; members still read it. Staff only. */
|
|
166
168
|
export const COMMUNITY_STATUS_VALUES = ['active', 'archived'];
|
|
167
169
|
export const communityStatusSchema = z.enum(COMMUNITY_STATUS_VALUES);
|
|
168
|
-
|
|
170
|
+
/**
|
|
171
|
+
* Whether a community may take type `to` now (0.18.0): ONE rule for the
|
|
172
|
+
* server's refusal (`COMMUNITY_ARCHIVED`) and the screen's choice. An
|
|
173
|
+
* archived community lets nobody new in, so it may be narrowed (private,
|
|
174
|
+
* hidden) but never opened to public, which would let its waiting requests in.
|
|
175
|
+
*/
|
|
176
|
+
export function communityTypeChangeAllowed(status, to) {
|
|
177
|
+
return !(status === 'archived' && to === 'public');
|
|
178
|
+
}
|
|
179
|
+
/** How staff decided a suggestion (0.18.0: named, for the bell and the backend's model). */
|
|
180
|
+
export const COMMUNITY_SUGGESTION_DECISION_VALUES = ['approved', 'declined'];
|
|
181
|
+
export const communitySuggestionDecisionSchema = z.enum(COMMUNITY_SUGGESTION_DECISION_VALUES);
|
|
182
|
+
export const COMMUNITY_SUGGESTION_STATUS_VALUES = [
|
|
183
|
+
'open',
|
|
184
|
+
...COMMUNITY_SUGGESTION_DECISION_VALUES,
|
|
185
|
+
];
|
|
169
186
|
export const communitySuggestionStatusSchema = z.enum(COMMUNITY_SUGGESTION_STATUS_VALUES);
|
|
170
187
|
// ─── Read shapes ─────────────────────────────────────────────────────────────
|
|
171
188
|
/**
|
|
@@ -221,12 +238,25 @@ export const communityViewerSchema = communityCardViewerSchema.extend({
|
|
|
221
238
|
canRequest: z.boolean(),
|
|
222
239
|
/** Active member, community not archived: the composer. */
|
|
223
240
|
canPost: z.boolean(),
|
|
224
|
-
/**
|
|
241
|
+
/**
|
|
242
|
+
* Active member who is not its last admin, or the last admin of a community
|
|
243
|
+
* nobody else is in (0.18.0): their leaving ARCHIVES it, nothing deleted,
|
|
244
|
+
* since there is no one to hand it to. A last admin with members hands it
|
|
245
|
+
* over first (`COMMUNITY_LAST_ADMIN`).
|
|
246
|
+
*/
|
|
225
247
|
canLeave: z.boolean(),
|
|
248
|
+
/**
|
|
249
|
+
* Leaving ARCHIVES it (0.18.0): the viewer is its last admin and nobody else
|
|
250
|
+
* is in it, counted as leaving counts. The server's answer, so the dialog
|
|
251
|
+
* never guesses from a stored count.
|
|
252
|
+
*/
|
|
253
|
+
leaveArchives: z.boolean(),
|
|
226
254
|
/**
|
|
227
255
|
* Moderators and admins (and managers, super admins): requests, invites,
|
|
228
|
-
* pins, hiding, removing members. On an ARCHIVED community
|
|
229
|
-
* inviting, accepting
|
|
256
|
+
* pins, hiding, removing members. On an ARCHIVED community nobody new comes
|
|
257
|
+
* in: approving, inviting, accepting, pinning AND opening it to public
|
|
258
|
+
* (which would let waiting requests in, `communityTypeChangeAllowed`,
|
|
259
|
+
* 0.18.0) answer `COMMUNITY_ARCHIVED`; narrowing its type, declining,
|
|
230
260
|
* cancelling, removing, banning, roles and hiding still work.
|
|
231
261
|
*/
|
|
232
262
|
canModerate: z.boolean(),
|
|
@@ -380,10 +410,7 @@ const descriptionSchema = z.string().trim().min(1).max(COMMUNITY_DESCRIPTION_MAX
|
|
|
380
410
|
const rulesSchema = z
|
|
381
411
|
.array(z.string().trim().min(1).max(COMMUNITY_RULE_MAX))
|
|
382
412
|
.max(COMMUNITY_RULES_MAX);
|
|
383
|
-
const topicsSchema = z
|
|
384
|
-
.array(topicSchema)
|
|
385
|
-
.max(COMMUNITY_TOPICS_MAX)
|
|
386
|
-
.refine((topics) => new Set(topics).size === topics.length, {
|
|
413
|
+
const topicsSchema = z.array(topicSchema).max(COMMUNITY_TOPICS_MAX).refine(eachOnce, {
|
|
387
414
|
error: VALIDATION_MESSAGE.topicsDuplicate,
|
|
388
415
|
});
|
|
389
416
|
/**
|
|
@@ -438,7 +465,8 @@ export const setCommunityMemberRoleBodySchema = z.object({ role: communityRoleSc
|
|
|
438
465
|
/** `POST /communities/:id/bans` (admins): removes them if active, and keeps them out. */
|
|
439
466
|
export const banCommunityMemberBodySchema = z.object({
|
|
440
467
|
userId: objectIdSchema,
|
|
441
|
-
reason
|
|
468
|
+
/** Why, for the record. Blank means no reason (0.18.0: a blank box was refused). */
|
|
469
|
+
reason: optionalTrimmedString(COMMUNITY_BAN_REASON_MAX),
|
|
442
470
|
});
|
|
443
471
|
/**
|
|
444
472
|
* `POST /communities/:id/pins` (moderators): pin one of the community's posts
|