@trypattern/sdk 0.1.33 → 0.1.34

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (45) hide show
  1. package/dist/app.d.ts +6 -2
  2. package/dist/app.js +6 -1
  3. package/dist/blocks.js +11 -3
  4. package/dist/bookings.d.ts +78 -0
  5. package/dist/bookings.js +7 -1
  6. package/dist/bookingsStore.d.ts +78 -0
  7. package/dist/cli/app.js +17 -2
  8. package/dist/cli/requests.d.ts +5 -0
  9. package/dist/cli/requests.js +115 -0
  10. package/dist/components/AppFrame.js +12 -2
  11. package/dist/components/MenuItems.d.ts +1 -0
  12. package/dist/components/MenuItems.js +13 -2
  13. package/dist/components/SegmentedControl.d.ts +1 -0
  14. package/dist/components/SegmentedControl.js +9 -2
  15. package/dist/components/Sidebar.d.ts +1 -0
  16. package/dist/components/Sidebar.js +18 -2
  17. package/dist/components/TableRow.d.ts +2 -1
  18. package/dist/components/TableRow.js +5 -2
  19. package/dist/components/icons.js +1 -2
  20. package/dist/index.d.ts +2 -0
  21. package/dist/index.js +1 -0
  22. package/dist/inquiriesStore.d.ts +134 -0
  23. package/dist/inquiriesStore.js +64 -0
  24. package/dist/patternAccess.d.ts +8 -2
  25. package/dist/patternAccess.js +17 -5
  26. package/dist/publishWire.d.ts +866 -0
  27. package/dist/publishWire.js +78 -0
  28. package/dist/requests.d.ts +361 -0
  29. package/dist/requests.js +180 -0
  30. package/dist/schema.d.ts +2 -0
  31. package/dist/schema.js +1 -0
  32. package/dist/server/authService.d.ts +1 -0
  33. package/dist/server/bookings.d.ts +2 -9
  34. package/dist/server/bookings.js +149 -31
  35. package/dist/server/createServer.js +4 -0
  36. package/dist/server/env.d.ts +3 -0
  37. package/dist/server/index.d.ts +1 -0
  38. package/dist/server/index.js +1 -0
  39. package/dist/server/inquiries.d.ts +9 -0
  40. package/dist/server/inquiries.js +150 -0
  41. package/dist/server/patternViewer.js +7 -1
  42. package/dist/server/requests.d.ts +76 -0
  43. package/dist/server/requests.js +328 -0
  44. package/dist/server/services.js +9 -1
  45. package/package.json +1 -1
@@ -2,6 +2,9 @@ import { z } from 'zod';
2
2
  import { appTitle } from "./appTitle.js";
3
3
  export { appTitle };
4
4
  export { ASSERTION_SECONDS, MEDIA_WRITE, NEXT_PAGE_HEADER, TABLES_READ, TABLES_WRITE, assertionKey, signAssertion } from "./patternAccess.js";
5
+ export { REQUESTS_ACT, REQUESTS_READ } from "./patternAccess.js";
6
+ export { REQUESTS_PATH, REQUEST_SYNC_PAGE, requestBound, requestCard, requestSync } from "./requests.js";
7
+ import { requestCard } from "./requests.js";
5
8
  import { call, defineServices } from "./services.js";
6
9
  export const DASHBOARD_URL = 'https://onpattern.app';
7
10
  export const APPS_DOMAIN = 'onpattern.app';
@@ -302,6 +305,34 @@ export const changeSet = z.object({
302
305
  changes: z.array(dataChange),
303
306
  outcomes: z.array(changeOutcome).nullable()
304
307
  });
308
+ export const REPLY_LIMIT = 5000;
309
+ export const requestMessage = z.object({
310
+ id: z.string(),
311
+ kind: z.enum(['reply', 'accepted', 'declined']),
312
+ text: z.string(),
313
+ status: z.enum(['sending', 'sent', 'failed']),
314
+ problem: z.string().nullable(),
315
+ createdAt: z.string(),
316
+ sentAt: z.string().nullable()
317
+ });
318
+ export const requestDraft = z.object({
319
+ id: z.string(),
320
+ text: z.string(),
321
+ asked: z.string(),
322
+ device: z.string(),
323
+ createdAt: z.string()
324
+ });
325
+ export const requestEntry = requestCard.extend({
326
+ isUnread: z.boolean(),
327
+ messages: z.array(requestMessage),
328
+ draft: requestDraft.nullable()
329
+ });
330
+ export const requestList = z.object({
331
+ status: z.enum(['ready', 'outdated', 'none']),
332
+ requests: z.array(requestEntry),
333
+ syncedAt: z.string().nullable()
334
+ });
335
+ const operation = z.string().min(8).max(100);
305
336
  export const publishServices = defineServices({
306
337
  apps: {
307
338
  list: call({ get: '/apps', reply: z.array(appSummary) }),
@@ -411,6 +442,53 @@ export const publishServices = defineServices({
411
442
  }),
412
443
  undo: call({ post: '/apps/:name/changes/:id/undo', reply: changeSet })
413
444
  },
445
+ requests: {
446
+ list: call({ get: '/apps/:name/requests', reply: requestList }),
447
+ deliver: call({
448
+ post: '/apps/:name/requests/deliver',
449
+ reply: requestList
450
+ }),
451
+ open: call({
452
+ post: '/apps/:name/requests/:source/:id/open',
453
+ reply: requestEntry
454
+ }),
455
+ act: call({
456
+ post: '/apps/:name/requests/:source/:id/act',
457
+ input: {
458
+ action: z.enum(['accept', 'decline', 'done']),
459
+ revision: z.number().int(),
460
+ operation
461
+ },
462
+ reply: requestEntry
463
+ }),
464
+ reply: call({
465
+ post: '/apps/:name/requests/:source/:id/reply',
466
+ input: {
467
+ text: z.string().trim().min(1).max(REPLY_LIMIT),
468
+ revision: z.number().int(),
469
+ operation,
470
+ draft: z.string().optional()
471
+ },
472
+ reply: requestEntry
473
+ }),
474
+ retry: call({
475
+ post: '/apps/:name/requests/:source/:id/retry',
476
+ input: { message: z.string() },
477
+ reply: requestEntry
478
+ }),
479
+ draft: call({
480
+ post: '/apps/:name/requests/:source/:id/drafts',
481
+ input: {
482
+ text: z.string().trim().min(1).max(REPLY_LIMIT),
483
+ asked: z.string().trim().min(1).max(1000)
484
+ },
485
+ reply: requestDraft
486
+ }),
487
+ discard: call({
488
+ post: '/apps/:name/requests/:source/:id/drafts/:draft/discard',
489
+ reply: requestEntry
490
+ })
491
+ },
414
492
  logins: {
415
493
  read: call({ get: '/cli/logins/:approval', reply: loginToApprove }),
416
494
  approve: call({
@@ -0,0 +1,361 @@
1
+ import { z } from 'zod';
2
+ import type { Table } from './table.ts';
3
+ export declare const REQUEST_KINDS: readonly ["booking", "inquiry"];
4
+ export declare const REQUEST_ACTIONS: readonly ["accept", "decline", "reply", "done"];
5
+ export declare const REQUEST_STATUSES: readonly ["requested", "accepted", "declined", "cancelled", "open", "replied", "done"];
6
+ export declare const REQUEST_EVENTS: readonly ["received", "accepted", "declined", "replied", "done"];
7
+ export declare const NOTICE_STATUSES: readonly ["pending", "sending", "sent", "failed"];
8
+ export declare const REQUESTS_PATH = "/api/pattern/requests";
9
+ export declare const REQUEST_SYNC_PAGE = 200;
10
+ export declare const requestStates: import("./table.ts").TableOf<"requestStates", {
11
+ readonly columns: {
12
+ readonly source: z.ZodString;
13
+ readonly requestId: z.ZodString;
14
+ readonly state: z.ZodEnum<{
15
+ done: "done";
16
+ open: "open";
17
+ }>;
18
+ readonly revision: z.ZodNumber;
19
+ readonly sequence: z.ZodNumber;
20
+ readonly updatedAt: z.ZodString;
21
+ };
22
+ readonly access: {
23
+ readonly read: "server";
24
+ readonly create: "server";
25
+ readonly update: "server";
26
+ readonly delete: "server";
27
+ };
28
+ readonly writes: "confirmed";
29
+ }>;
30
+ export declare const requestEvents: import("./table.ts").TableOf<"requestEvents", {
31
+ readonly columns: {
32
+ readonly source: z.ZodString;
33
+ readonly requestId: z.ZodString;
34
+ readonly kind: z.ZodEnum<{
35
+ done: "done";
36
+ accepted: "accepted";
37
+ declined: "declined";
38
+ replied: "replied";
39
+ received: "received";
40
+ }>;
41
+ };
42
+ readonly access: {
43
+ readonly read: "server";
44
+ readonly create: "server";
45
+ readonly update: "server";
46
+ readonly delete: "server";
47
+ };
48
+ readonly writes: "confirmed";
49
+ }>;
50
+ export declare const requestOutbox: import("./table.ts").TableOf<"requestOutbox", {
51
+ readonly columns: {
52
+ readonly source: z.ZodString;
53
+ readonly requestId: z.ZodString;
54
+ readonly subject: z.ZodString;
55
+ readonly text: z.ZodString;
56
+ readonly replyTo: z.ZodString;
57
+ readonly status: z.ZodEnum<{
58
+ failed: "failed";
59
+ pending: "pending";
60
+ sent: "sent";
61
+ sending: "sending";
62
+ }>;
63
+ readonly attempts: z.ZodNumber;
64
+ readonly nextAt: z.ZodNullable<z.ZodString>;
65
+ readonly sentAt: z.ZodNullable<z.ZodString>;
66
+ readonly claimedAt: z.ZodNullable<z.ZodString>;
67
+ };
68
+ readonly access: {
69
+ readonly read: "server";
70
+ readonly create: "server";
71
+ readonly update: "server";
72
+ readonly delete: "server";
73
+ };
74
+ readonly writes: "confirmed";
75
+ }>;
76
+ export declare const requestOperations: import("./table.ts").TableOf<"requestOperations", {
77
+ readonly columns: {
78
+ readonly result: z.ZodString;
79
+ };
80
+ readonly access: {
81
+ readonly read: "server";
82
+ readonly create: "server";
83
+ readonly update: "server";
84
+ readonly delete: "server";
85
+ };
86
+ readonly writes: "confirmed";
87
+ }>;
88
+ export declare const requestTables: {
89
+ requestStates: import("./table.ts").TableOf<"requestStates", {
90
+ readonly columns: {
91
+ readonly source: z.ZodString;
92
+ readonly requestId: z.ZodString;
93
+ readonly state: z.ZodEnum<{
94
+ done: "done";
95
+ open: "open";
96
+ }>;
97
+ readonly revision: z.ZodNumber;
98
+ readonly sequence: z.ZodNumber;
99
+ readonly updatedAt: z.ZodString;
100
+ };
101
+ readonly access: {
102
+ readonly read: "server";
103
+ readonly create: "server";
104
+ readonly update: "server";
105
+ readonly delete: "server";
106
+ };
107
+ readonly writes: "confirmed";
108
+ }>;
109
+ requestEvents: import("./table.ts").TableOf<"requestEvents", {
110
+ readonly columns: {
111
+ readonly source: z.ZodString;
112
+ readonly requestId: z.ZodString;
113
+ readonly kind: z.ZodEnum<{
114
+ done: "done";
115
+ accepted: "accepted";
116
+ declined: "declined";
117
+ replied: "replied";
118
+ received: "received";
119
+ }>;
120
+ };
121
+ readonly access: {
122
+ readonly read: "server";
123
+ readonly create: "server";
124
+ readonly update: "server";
125
+ readonly delete: "server";
126
+ };
127
+ readonly writes: "confirmed";
128
+ }>;
129
+ requestOutbox: import("./table.ts").TableOf<"requestOutbox", {
130
+ readonly columns: {
131
+ readonly source: z.ZodString;
132
+ readonly requestId: z.ZodString;
133
+ readonly subject: z.ZodString;
134
+ readonly text: z.ZodString;
135
+ readonly replyTo: z.ZodString;
136
+ readonly status: z.ZodEnum<{
137
+ failed: "failed";
138
+ pending: "pending";
139
+ sent: "sent";
140
+ sending: "sending";
141
+ }>;
142
+ readonly attempts: z.ZodNumber;
143
+ readonly nextAt: z.ZodNullable<z.ZodString>;
144
+ readonly sentAt: z.ZodNullable<z.ZodString>;
145
+ readonly claimedAt: z.ZodNullable<z.ZodString>;
146
+ };
147
+ readonly access: {
148
+ readonly read: "server";
149
+ readonly create: "server";
150
+ readonly update: "server";
151
+ readonly delete: "server";
152
+ };
153
+ readonly writes: "confirmed";
154
+ }>;
155
+ requestOperations: import("./table.ts").TableOf<"requestOperations", {
156
+ readonly columns: {
157
+ readonly result: z.ZodString;
158
+ };
159
+ readonly access: {
160
+ readonly read: "server";
161
+ readonly create: "server";
162
+ readonly update: "server";
163
+ readonly delete: "server";
164
+ };
165
+ readonly writes: "confirmed";
166
+ }>;
167
+ };
168
+ export type RequestKind = (typeof REQUEST_KINDS)[number];
169
+ export type RequestAction = (typeof REQUEST_ACTIONS)[number];
170
+ export declare const requestField: z.ZodObject<{
171
+ label: z.ZodString;
172
+ value: z.ZodString;
173
+ }, z.core.$strip>;
174
+ export declare const requestCard: z.ZodObject<{
175
+ source: z.ZodString;
176
+ id: z.ZodString;
177
+ kind: z.ZodEnum<{
178
+ booking: "booking";
179
+ inquiry: "inquiry";
180
+ }>;
181
+ title: z.ZodString;
182
+ label: z.ZodString;
183
+ summary: z.ZodString;
184
+ name: z.ZodString;
185
+ email: z.ZodString;
186
+ when: z.ZodNullable<z.ZodString>;
187
+ whenDetail: z.ZodNullable<z.ZodString>;
188
+ fields: z.ZodArray<z.ZodObject<{
189
+ label: z.ZodString;
190
+ value: z.ZodString;
191
+ }, z.core.$strip>>;
192
+ contact: z.ZodArray<z.ZodObject<{
193
+ label: z.ZodString;
194
+ value: z.ZodString;
195
+ }, z.core.$strip>>;
196
+ message: z.ZodString;
197
+ status: z.ZodEnum<{
198
+ done: "done";
199
+ requested: "requested";
200
+ accepted: "accepted";
201
+ declined: "declined";
202
+ cancelled: "cancelled";
203
+ open: "open";
204
+ replied: "replied";
205
+ }>;
206
+ needsAnswer: z.ZodBoolean;
207
+ actions: z.ZodArray<z.ZodEnum<{
208
+ done: "done";
209
+ accept: "accept";
210
+ decline: "decline";
211
+ reply: "reply";
212
+ }>>;
213
+ revision: z.ZodNumber;
214
+ receivedAt: z.ZodString;
215
+ history: z.ZodArray<z.ZodObject<{
216
+ kind: z.ZodEnum<{
217
+ done: "done";
218
+ accepted: "accepted";
219
+ declined: "declined";
220
+ replied: "replied";
221
+ received: "received";
222
+ }>;
223
+ at: z.ZodString;
224
+ }, z.core.$strip>>;
225
+ notice: z.ZodNullable<z.ZodObject<{
226
+ status: z.ZodEnum<{
227
+ failed: "failed";
228
+ pending: "pending";
229
+ sent: "sent";
230
+ sending: "sending";
231
+ }>;
232
+ attempts: z.ZodNumber;
233
+ at: z.ZodNullable<z.ZodString>;
234
+ }, z.core.$strip>>;
235
+ }, z.core.$strip>;
236
+ export type RequestCard = z.output<typeof requestCard>;
237
+ export declare const requestSync: z.ZodObject<{
238
+ cursor: z.ZodNumber;
239
+ requests: z.ZodArray<z.ZodObject<{
240
+ source: z.ZodString;
241
+ id: z.ZodString;
242
+ kind: z.ZodEnum<{
243
+ booking: "booking";
244
+ inquiry: "inquiry";
245
+ }>;
246
+ title: z.ZodString;
247
+ label: z.ZodString;
248
+ summary: z.ZodString;
249
+ name: z.ZodString;
250
+ email: z.ZodString;
251
+ when: z.ZodNullable<z.ZodString>;
252
+ whenDetail: z.ZodNullable<z.ZodString>;
253
+ fields: z.ZodArray<z.ZodObject<{
254
+ label: z.ZodString;
255
+ value: z.ZodString;
256
+ }, z.core.$strip>>;
257
+ contact: z.ZodArray<z.ZodObject<{
258
+ label: z.ZodString;
259
+ value: z.ZodString;
260
+ }, z.core.$strip>>;
261
+ message: z.ZodString;
262
+ status: z.ZodEnum<{
263
+ done: "done";
264
+ requested: "requested";
265
+ accepted: "accepted";
266
+ declined: "declined";
267
+ cancelled: "cancelled";
268
+ open: "open";
269
+ replied: "replied";
270
+ }>;
271
+ needsAnswer: z.ZodBoolean;
272
+ actions: z.ZodArray<z.ZodEnum<{
273
+ done: "done";
274
+ accept: "accept";
275
+ decline: "decline";
276
+ reply: "reply";
277
+ }>>;
278
+ revision: z.ZodNumber;
279
+ receivedAt: z.ZodString;
280
+ history: z.ZodArray<z.ZodObject<{
281
+ kind: z.ZodEnum<{
282
+ done: "done";
283
+ accepted: "accepted";
284
+ declined: "declined";
285
+ replied: "replied";
286
+ received: "received";
287
+ }>;
288
+ at: z.ZodString;
289
+ }, z.core.$strip>>;
290
+ notice: z.ZodNullable<z.ZodObject<{
291
+ status: z.ZodEnum<{
292
+ failed: "failed";
293
+ pending: "pending";
294
+ sent: "sent";
295
+ sending: "sending";
296
+ }>;
297
+ attempts: z.ZodNumber;
298
+ at: z.ZodNullable<z.ZodString>;
299
+ }, z.core.$strip>>;
300
+ }, z.core.$strip>>;
301
+ }, z.core.$strip>;
302
+ export type RequestSync = z.output<typeof requestSync>;
303
+ export declare const requestAct: z.ZodObject<{
304
+ source: z.ZodString;
305
+ id: z.ZodString;
306
+ action: z.ZodEnum<{
307
+ done: "done";
308
+ accept: "accept";
309
+ decline: "decline";
310
+ reply: "reply";
311
+ }>;
312
+ revision: z.ZodNumber;
313
+ operation: z.ZodString;
314
+ }, z.core.$strip>;
315
+ export type RequestAct = z.output<typeof requestAct>;
316
+ export declare function requestBound(act: RequestAct): Promise<string>;
317
+ type ColumnOf<T extends Table> = keyof T['columns'] & string;
318
+ export type InquiryOptions<T extends Table> = {
319
+ source: string;
320
+ title: string;
321
+ form: string;
322
+ name: ColumnOf<T>;
323
+ email: ColumnOf<T>;
324
+ fields: Partial<Readonly<Record<ColumnOf<T>, string>>>;
325
+ summary?: ColumnOf<T>;
326
+ message?: ColumnOf<T>;
327
+ when?: {
328
+ field: ColumnOf<T>;
329
+ detail: string;
330
+ };
331
+ };
332
+ export type Inquiry = {
333
+ readonly source: string;
334
+ readonly table: Table;
335
+ readonly title: string;
336
+ readonly form: string;
337
+ readonly name: string;
338
+ readonly email: string;
339
+ readonly fields: readonly {
340
+ key: string;
341
+ label: string;
342
+ }[];
343
+ readonly summary: string | null;
344
+ readonly message: string | null;
345
+ readonly when: {
346
+ field: string;
347
+ detail: string;
348
+ } | null;
349
+ };
350
+ export declare function inquiry<T extends Table>(table: T, options: InquiryOptions<T>): Inquiry;
351
+ export declare const inquiryValue: z.ZodUnion<readonly [z.ZodString, z.ZodNumber, z.ZodBoolean, z.ZodNull]>;
352
+ export declare const inquiryServices: {
353
+ readonly inquiries: {
354
+ readonly send: NoInfer<import("./services.ts").ServiceCall<"/requests/:source", {
355
+ fields: z.ZodRecord<z.ZodString, z.ZodUnion<readonly [z.ZodString, z.ZodNumber, z.ZodBoolean, z.ZodNull]>>;
356
+ }, z.ZodObject<{
357
+ id: z.ZodString;
358
+ }, z.core.$strip>, false>>;
359
+ };
360
+ };
361
+ export {};
@@ -0,0 +1,180 @@
1
+ import { z } from 'zod';
2
+ import { call, defineServices } from "./services.js";
3
+ import { patternTable } from "./table.js";
4
+ export const REQUEST_KINDS = ['booking', 'inquiry'];
5
+ export const REQUEST_ACTIONS = ['accept', 'decline', 'reply', 'done'];
6
+ export const REQUEST_STATUSES = [
7
+ 'requested',
8
+ 'accepted',
9
+ 'declined',
10
+ 'cancelled',
11
+ 'open',
12
+ 'replied',
13
+ 'done'
14
+ ];
15
+ export const REQUEST_EVENTS = [
16
+ 'received',
17
+ 'accepted',
18
+ 'declined',
19
+ 'replied',
20
+ 'done'
21
+ ];
22
+ export const NOTICE_STATUSES = ['pending', 'sending', 'sent', 'failed'];
23
+ export const REQUESTS_PATH = '/api/pattern/requests';
24
+ export const REQUEST_SYNC_PAGE = 200;
25
+ export const requestStates = patternTable('requestStates', {
26
+ columns: {
27
+ source: z.string(),
28
+ requestId: z.string(),
29
+ state: z.enum(['open', 'done']),
30
+ revision: z.number().int(),
31
+ sequence: z.number().int(),
32
+ updatedAt: z.string()
33
+ },
34
+ access: {
35
+ read: 'server',
36
+ create: 'server',
37
+ update: 'server',
38
+ delete: 'server'
39
+ },
40
+ writes: 'confirmed'
41
+ });
42
+ export const requestEvents = patternTable('requestEvents', {
43
+ columns: {
44
+ source: z.string(),
45
+ requestId: z.string(),
46
+ kind: z.enum(REQUEST_EVENTS)
47
+ },
48
+ access: {
49
+ read: 'server',
50
+ create: 'server',
51
+ update: 'server',
52
+ delete: 'server'
53
+ },
54
+ writes: 'confirmed'
55
+ });
56
+ export const requestOutbox = patternTable('requestOutbox', {
57
+ columns: {
58
+ source: z.string(),
59
+ requestId: z.string(),
60
+ subject: z.string(),
61
+ text: z.string(),
62
+ replyTo: z.string(),
63
+ status: z.enum(NOTICE_STATUSES),
64
+ attempts: z.number().int(),
65
+ nextAt: z.string().nullable(),
66
+ sentAt: z.string().nullable(),
67
+ claimedAt: z.string().nullable()
68
+ },
69
+ access: {
70
+ read: 'server',
71
+ create: 'server',
72
+ update: 'server',
73
+ delete: 'server'
74
+ },
75
+ writes: 'confirmed'
76
+ });
77
+ export const requestOperations = patternTable('requestOperations', {
78
+ columns: { result: z.string() },
79
+ access: {
80
+ read: 'server',
81
+ create: 'server',
82
+ update: 'server',
83
+ delete: 'server'
84
+ },
85
+ writes: 'confirmed'
86
+ });
87
+ export const requestTables = {
88
+ requestStates,
89
+ requestEvents,
90
+ requestOutbox,
91
+ requestOperations
92
+ };
93
+ export const requestField = z.object({ label: z.string(), value: z.string() });
94
+ export const requestCard = z.object({
95
+ source: z.string(),
96
+ id: z.string(),
97
+ kind: z.enum(REQUEST_KINDS),
98
+ title: z.string(),
99
+ label: z.string(),
100
+ summary: z.string(),
101
+ name: z.string(),
102
+ email: z.string(),
103
+ when: z.string().nullable(),
104
+ whenDetail: z.string().nullable(),
105
+ fields: z.array(requestField),
106
+ contact: z.array(requestField),
107
+ message: z.string(),
108
+ status: z.enum(REQUEST_STATUSES),
109
+ needsAnswer: z.boolean(),
110
+ actions: z.array(z.enum(REQUEST_ACTIONS)),
111
+ revision: z.number().int(),
112
+ receivedAt: z.string(),
113
+ history: z.array(z.object({ kind: z.enum(REQUEST_EVENTS), at: z.string() })),
114
+ notice: z
115
+ .object({
116
+ status: z.enum(NOTICE_STATUSES),
117
+ attempts: z.number().int(),
118
+ at: z.string().nullable()
119
+ })
120
+ .nullable()
121
+ });
122
+ export const requestSync = z.object({
123
+ cursor: z.number().int(),
124
+ requests: z.array(requestCard)
125
+ });
126
+ export const requestAct = z.object({
127
+ source: z.string().min(1).max(60),
128
+ id: z.string().min(1).max(200),
129
+ action: z.enum(REQUEST_ACTIONS),
130
+ revision: z.number().int(),
131
+ operation: z.string().min(8).max(100)
132
+ });
133
+ export async function requestBound(act) {
134
+ const digest = await crypto.subtle.digest('SHA-256', new TextEncoder().encode(JSON.stringify([
135
+ act.source,
136
+ act.id,
137
+ act.action,
138
+ act.revision,
139
+ act.operation
140
+ ])));
141
+ return [...new Uint8Array(digest)]
142
+ .map((byte) => byte.toString(16).padStart(2, '0'))
143
+ .join('');
144
+ }
145
+ const SOURCE_NAME = /^[a-z][a-zA-Z0-9]{0,39}$/;
146
+ export function inquiry(table, options) {
147
+ if (!SOURCE_NAME.test(options.source) || options.source === 'bookings') {
148
+ throw new Error(`inquiry source '${options.source}' needs a short camelCase name of its own, like 'orders'`);
149
+ }
150
+ if (table.access.create !== 'server') {
151
+ throw new Error(`${table.name} holds the ${options.source} inquiry, so its create access is 'server': visitors send through this.stores.inquiries.send('${options.source}', …), which also tells the owner`);
152
+ }
153
+ return {
154
+ source: options.source,
155
+ table,
156
+ title: options.title,
157
+ form: options.form,
158
+ name: options.name,
159
+ email: options.email,
160
+ fields: Object.entries(options.fields).flatMap(([key, label]) => typeof label === 'string' ? [{ key, label }] : []),
161
+ summary: options.summary ?? null,
162
+ message: options.message ?? null,
163
+ when: options.when ?? null
164
+ };
165
+ }
166
+ export const inquiryValue = z.union([
167
+ z.string(),
168
+ z.number(),
169
+ z.boolean(),
170
+ z.null()
171
+ ]);
172
+ export const inquiryServices = defineServices({
173
+ inquiries: {
174
+ send: call({
175
+ post: '/requests/:source',
176
+ input: { fields: z.record(z.string(), inquiryValue) },
177
+ reply: z.object({ id: z.string() })
178
+ })
179
+ }
180
+ });
package/dist/schema.d.ts CHANGED
@@ -2,6 +2,8 @@ export { call, defineServices } from './services.ts';
2
2
  export type { CallInput, CallReply, HandlerInput, ServiceCall, ServiceMemory, Services, UploadOptions } from './services.ts';
3
3
  export { media } from './media.ts';
4
4
  export { bookingTables } from './bookings.ts';
5
+ export { inquiry, requestTables } from './requests.ts';
6
+ export type { Inquiry, InquiryOptions } from './requests.ts';
5
7
  export type { BookingDay, BookingRequest, BookingRequestFields, BookingRules, BookingSlot, BookingStatus, BookingWindow } from './bookings.ts';
6
8
  export type { Media, MediaImage, Starter, StarterPhoto } from './media.ts';
7
9
  export { defineTables } from './table.ts';
package/dist/schema.js CHANGED
@@ -1,4 +1,5 @@
1
1
  export { call, defineServices } from "./services.js";
2
2
  export { media } from "./media.js";
3
3
  export { bookingTables } from "./bookings.js";
4
+ export { inquiry, requestTables } from "./requests.js";
4
5
  export { defineTables } from "./table.js";
@@ -11,6 +11,7 @@ export type OwnerNote = {
11
11
  subject: string;
12
12
  text: string;
13
13
  replyTo?: string;
14
+ key?: string;
14
15
  };
15
16
  export declare function authServiceFor(env: ServerBindings): AuthService | undefined;
16
17
  export declare function notifyOwner(env: ServerBindings, note: OwnerNote): Promise<boolean>;
@@ -1,13 +1,6 @@
1
- import type { Context } from 'hono';
2
- import type { BookingRequest } from '../bookings.ts';
3
- import type { ServerBlock, ServerEnv } from './env.ts';
1
+ import type { ServerBlock } from './env.ts';
4
2
  export type BookingsOptions = {
5
3
  timezone: string;
6
4
  managePath?: string;
7
5
  };
8
- export type BookingEmail = {
9
- kind: 'requested' | 'accepted' | 'declined';
10
- request: BookingRequest;
11
- };
12
- export declare function sendBookingEmail(c: Context<ServerEnv>, email: BookingEmail): Promise<void>;
13
- export declare function bookings({ timezone, managePath }: BookingsOptions): ServerBlock;
6
+ export declare function bookings({ timezone }: BookingsOptions): ServerBlock;