@bunizao/contracts 0.3.0 → 0.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/dist/index.d.ts CHANGED
@@ -3,6 +3,7 @@ export * from './admin';
3
3
  export * from './comments';
4
4
  export * from './content';
5
5
  export * from './listening';
6
+ export * from './messages';
6
7
  export * from './mood';
7
8
  export * from './notify';
8
9
  export * from './routes';
package/dist/index.js CHANGED
@@ -85,6 +85,13 @@ function parsePostLocaleTag(tagName) {
85
85
  }
86
86
  return canonicalSlug ? { locale, canonicalSlug } : { locale };
87
87
  }
88
+ // src/messages.ts
89
+ var MESSAGE_LOCALES = ["zh", "en"];
90
+ var MESSAGE_MIN_BODY_LENGTH = 2;
91
+ var MESSAGE_MAX_BODY_LENGTH = 4000;
92
+ var MESSAGE_MAX_NAME_LENGTH = 32;
93
+ var MESSAGE_STATES = ["new", "read", "replied", "archived", "spam"];
94
+
88
95
  // src/mood.ts
89
96
  var MOOD_SENTIMENT_LABELS = ["joy", "calm", "melancholy", "anger", "anxiety", "neutral"];
90
97
  var MOOD_AI_MODELS = ["gpt-5.5", "gpt-5", "claude-sonnet-4.6"];
@@ -109,6 +116,7 @@ var MOOD_MEDIA_PROXY_BASE_PATH = "/v2/media";
109
116
  var LISTENING_PATH = "/v2/listening";
110
117
  var COMMENTS_PATH = "/v2/comments";
111
118
  var COMMENT_PATH_PREFIX = "/v2/comments/";
119
+ var OWNER_MESSAGES_PATH = "/v2/messages";
112
120
  var REACTIONS_PATH = "/v2/reactions";
113
121
  var REACTIONS_TOGGLE_PATH = "/v2/reactions/toggle";
114
122
  var READER_ME_PATH = "/v2/reader/me";
@@ -212,6 +220,11 @@ export {
212
220
  LEGACY_NOTIFY_BASE_PATH,
213
221
  LISTENING_ANALYTICS_EVENT_ENDPOINT,
214
222
  LISTENING_PATH,
223
+ MESSAGE_LOCALES,
224
+ MESSAGE_MAX_BODY_LENGTH,
225
+ MESSAGE_MAX_NAME_LENGTH,
226
+ MESSAGE_MIN_BODY_LENGTH,
227
+ MESSAGE_STATES,
215
228
  MODERATION_ACTIONS,
216
229
  MODERATION_REASONS,
217
230
  MOOD_AI_MODELS,
@@ -235,6 +248,7 @@ export {
235
248
  NOTIFY_GATE_PATH,
236
249
  NOTIFY_GATE_RELEASE_PATH,
237
250
  NOTIFY_GATE_STATES,
251
+ OWNER_MESSAGES_PATH,
238
252
  PING_PATH,
239
253
  REACTIONS_PATH,
240
254
  REACTIONS_TOGGLE_PATH,
@@ -0,0 +1,68 @@
1
+ /**
2
+ * Owner messages — the standalone form at /message.
3
+ *
4
+ * This is deliberately NOT the comments contract. A message is private by
5
+ * construction, not by moderation state: there is no `published`, no thread,
6
+ * no parent, no reactions, and no public read endpoint anywhere in this file.
7
+ * The comments stack answers "who may see this row"; here the answer is fixed
8
+ * at the storage layer, so a mis-written WHERE clause cannot leak one.
9
+ *
10
+ * What it does share with comments is everything that lives above the table:
11
+ * Turnstile, the honeypot and dwell tripwires, Akismet, the risk heuristics,
12
+ * reader identity, and the ops-bot notification. See site-api's
13
+ * features/messages/server/message-service.ts.
14
+ */
15
+ export declare const MESSAGE_LOCALES: readonly ['zh', 'en'];
16
+ export type MessageLocale = (typeof MESSAGE_LOCALES)[number];
17
+ /** Body bounds, shared by the form's client-side validation and the service. */
18
+ export declare const MESSAGE_MIN_BODY_LENGTH = 2;
19
+ export declare const MESSAGE_MAX_BODY_LENGTH = 4000;
20
+ export declare const MESSAGE_MAX_NAME_LENGTH = 32;
21
+ /**
22
+ * Triage, not moderation. Every value here is private; none of them makes a
23
+ * message visible to anyone but the owner, which is why there is no
24
+ * `published` member to accidentally set.
25
+ *
26
+ * new — landed, not yet looked at
27
+ * read — the owner has seen it
28
+ * replied — answered from Telegram; `repliedAt` is set
29
+ * archived — filed away by the owner
30
+ * spam — the risk stack or Akismet called it; never notified loudly
31
+ */
32
+ export declare const MESSAGE_STATES: readonly ['new', 'read', 'replied', 'archived', 'spam'];
33
+ export type MessageState = (typeof MESSAGE_STATES)[number];
34
+ export interface OwnerMessageCreateInput {
35
+ /** Plain text, MESSAGE_MIN_BODY_LENGTH–MESSAGE_MAX_BODY_LENGTH characters. */
36
+ body: string;
37
+ displayName: string;
38
+ /**
39
+ * Optional, and optional on purpose — the same "channeling beats blocking"
40
+ * call the comment box makes. Supplied, it must be valid: it triggers the
41
+ * shared lazy-verification mail, and only a verified address can ever
42
+ * receive the owner's reply.
43
+ */
44
+ email?: string;
45
+ turnstileToken: string;
46
+ /** Minted by the form on load; proves the submit was not instant. */
47
+ dwellToken: string;
48
+ /** Honeypot. Any non-empty value is a silent drop. */
49
+ website?: string;
50
+ locale?: MessageLocale;
51
+ }
52
+ export interface OwnerMessageCreateResult {
53
+ id: string;
54
+ createdAt: string;
55
+ /**
56
+ * Whether the owner's reply can actually reach the sender. True only when
57
+ * the address belongs to a verified reader — an address typed into a public
58
+ * form is not proof that its owner sent anything, so an unverified one is
59
+ * never mailed. False also when no address was given at all; the form uses
60
+ * this to decide whether the receipt promises a reply or not.
61
+ */
62
+ replyable: boolean;
63
+ /**
64
+ * A verification mail just went out to a not-yet-verified address. The
65
+ * receipt tells the sender to click it if they want an answer.
66
+ */
67
+ verificationSent: boolean;
68
+ }
@@ -0,0 +1,13 @@
1
+ // src/messages.ts
2
+ var MESSAGE_LOCALES = ["zh", "en"];
3
+ var MESSAGE_MIN_BODY_LENGTH = 2;
4
+ var MESSAGE_MAX_BODY_LENGTH = 4000;
5
+ var MESSAGE_MAX_NAME_LENGTH = 32;
6
+ var MESSAGE_STATES = ["new", "read", "replied", "archived", "spam"];
7
+ export {
8
+ MESSAGE_LOCALES,
9
+ MESSAGE_MAX_BODY_LENGTH,
10
+ MESSAGE_MAX_NAME_LENGTH,
11
+ MESSAGE_MIN_BODY_LENGTH,
12
+ MESSAGE_STATES
13
+ };
package/dist/routes.d.ts CHANGED
@@ -14,6 +14,7 @@ export declare const MOOD_MEDIA_PROXY_BASE_PATH: '/v2/media';
14
14
  export declare const LISTENING_PATH: '/v2/listening';
15
15
  export declare const COMMENTS_PATH: '/v2/comments';
16
16
  export declare const COMMENT_PATH_PREFIX: '/v2/comments/';
17
+ export declare const OWNER_MESSAGES_PATH: '/v2/messages';
17
18
  export declare const REACTIONS_PATH: '/v2/reactions';
18
19
  export declare const REACTIONS_TOGGLE_PATH: '/v2/reactions/toggle';
19
20
  export declare const READER_ME_PATH: '/v2/reader/me';
package/dist/routes.js CHANGED
@@ -15,6 +15,7 @@ var MOOD_MEDIA_PROXY_BASE_PATH = "/v2/media";
15
15
  var LISTENING_PATH = "/v2/listening";
16
16
  var COMMENTS_PATH = "/v2/comments";
17
17
  var COMMENT_PATH_PREFIX = "/v2/comments/";
18
+ var OWNER_MESSAGES_PATH = "/v2/messages";
18
19
  var REACTIONS_PATH = "/v2/reactions";
19
20
  var REACTIONS_TOGGLE_PATH = "/v2/reactions/toggle";
20
21
  var READER_ME_PATH = "/v2/reader/me";
@@ -61,6 +62,7 @@ export {
61
62
  MOOD_SEARCH_PATH,
62
63
  MUSICKIT_TOKEN_PATH,
63
64
  NOTIFY_BASE_PATH,
65
+ OWNER_MESSAGES_PATH,
64
66
  PING_PATH,
65
67
  REACTIONS_PATH,
66
68
  REACTIONS_TOGGLE_PATH,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@bunizao/contracts",
3
- "version": "0.3.0",
3
+ "version": "0.4.0",
4
4
  "description": "Shared TypeScript contracts for buxx.me services and clients.",
5
5
  "type": "module",
6
6
  "sideEffects": false,
@@ -53,6 +53,11 @@
53
53
  "import": "./dist/listening.js",
54
54
  "default": "./dist/listening.js"
55
55
  },
56
+ "./messages": {
57
+ "types": "./dist/messages.d.ts",
58
+ "import": "./dist/messages.js",
59
+ "default": "./dist/messages.js"
60
+ },
56
61
  "./mood": {
57
62
  "types": "./dist/mood.d.ts",
58
63
  "import": "./dist/mood.js",