@kelpie/schemas 0.1.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.
Files changed (158) hide show
  1. package/LICENSE +661 -0
  2. package/README.md +33 -0
  3. package/dist/account.d.ts +79 -0
  4. package/dist/account.d.ts.map +1 -0
  5. package/dist/account.js +66 -0
  6. package/dist/account.js.map +1 -0
  7. package/dist/activity.d.ts +23 -0
  8. package/dist/activity.d.ts.map +1 -0
  9. package/dist/activity.js +27 -0
  10. package/dist/activity.js.map +1 -0
  11. package/dist/agentTask.d.ts +97 -0
  12. package/dist/agentTask.d.ts.map +1 -0
  13. package/dist/agentTask.js +127 -0
  14. package/dist/agentTask.js.map +1 -0
  15. package/dist/candidate.d.ts +39 -0
  16. package/dist/candidate.d.ts.map +1 -0
  17. package/dist/candidate.js +40 -0
  18. package/dist/candidate.js.map +1 -0
  19. package/dist/company.d.ts +38 -0
  20. package/dist/company.d.ts.map +1 -0
  21. package/dist/company.js +57 -0
  22. package/dist/company.js.map +1 -0
  23. package/dist/dashboard.d.ts +112 -0
  24. package/dist/dashboard.d.ts.map +1 -0
  25. package/dist/dashboard.js +165 -0
  26. package/dist/dashboard.js.map +1 -0
  27. package/dist/deal.d.ts +40 -0
  28. package/dist/deal.d.ts.map +1 -0
  29. package/dist/deal.js +59 -0
  30. package/dist/deal.js.map +1 -0
  31. package/dist/decision.d.ts +46 -0
  32. package/dist/decision.d.ts.map +1 -0
  33. package/dist/decision.js +48 -0
  34. package/dist/decision.js.map +1 -0
  35. package/dist/form.d.ts +97 -0
  36. package/dist/form.d.ts.map +1 -0
  37. package/dist/form.js +98 -0
  38. package/dist/form.js.map +1 -0
  39. package/dist/formSubmission.d.ts +47 -0
  40. package/dist/formSubmission.d.ts.map +1 -0
  41. package/dist/formSubmission.js +47 -0
  42. package/dist/formSubmission.js.map +1 -0
  43. package/dist/handbookPage.d.ts +52 -0
  44. package/dist/handbookPage.d.ts.map +1 -0
  45. package/dist/handbookPage.js +56 -0
  46. package/dist/handbookPage.js.map +1 -0
  47. package/dist/importExport.d.ts +143 -0
  48. package/dist/importExport.d.ts.map +1 -0
  49. package/dist/importExport.js +239 -0
  50. package/dist/importExport.js.map +1 -0
  51. package/dist/index.d.ts +75 -0
  52. package/dist/index.d.ts.map +1 -0
  53. package/dist/index.js +45 -0
  54. package/dist/index.js.map +1 -0
  55. package/dist/invite.d.ts +35 -0
  56. package/dist/invite.d.ts.map +1 -0
  57. package/dist/invite.js +31 -0
  58. package/dist/invite.js.map +1 -0
  59. package/dist/mcpTool.d.ts +26 -0
  60. package/dist/mcpTool.d.ts.map +1 -0
  61. package/dist/mcpTool.js +13 -0
  62. package/dist/mcpTool.js.map +1 -0
  63. package/dist/member.d.ts +26 -0
  64. package/dist/member.d.ts.map +1 -0
  65. package/dist/member.js +24 -0
  66. package/dist/member.js.map +1 -0
  67. package/dist/moduleSetting.d.ts +19 -0
  68. package/dist/moduleSetting.d.ts.map +1 -0
  69. package/dist/moduleSetting.js +16 -0
  70. package/dist/moduleSetting.js.map +1 -0
  71. package/dist/note.d.ts +34 -0
  72. package/dist/note.d.ts.map +1 -0
  73. package/dist/note.js +35 -0
  74. package/dist/note.js.map +1 -0
  75. package/dist/opportunity.d.ts +30 -0
  76. package/dist/opportunity.d.ts.map +1 -0
  77. package/dist/opportunity.js +41 -0
  78. package/dist/opportunity.js.map +1 -0
  79. package/dist/partnership.d.ts +36 -0
  80. package/dist/partnership.d.ts.map +1 -0
  81. package/dist/partnership.js +50 -0
  82. package/dist/partnership.js.map +1 -0
  83. package/dist/person.d.ts +45 -0
  84. package/dist/person.d.ts.map +1 -0
  85. package/dist/person.js +60 -0
  86. package/dist/person.js.map +1 -0
  87. package/dist/pipelineStage.d.ts +29 -0
  88. package/dist/pipelineStage.d.ts.map +1 -0
  89. package/dist/pipelineStage.js +38 -0
  90. package/dist/pipelineStage.js.map +1 -0
  91. package/dist/planItem.d.ts +43 -0
  92. package/dist/planItem.d.ts.map +1 -0
  93. package/dist/planItem.js +44 -0
  94. package/dist/planItem.js.map +1 -0
  95. package/dist/position.d.ts +22 -0
  96. package/dist/position.d.ts.map +1 -0
  97. package/dist/position.js +25 -0
  98. package/dist/position.js.map +1 -0
  99. package/dist/raise.d.ts +38 -0
  100. package/dist/raise.d.ts.map +1 -0
  101. package/dist/raise.js +53 -0
  102. package/dist/raise.js.map +1 -0
  103. package/dist/role.d.ts +21 -0
  104. package/dist/role.d.ts.map +1 -0
  105. package/dist/role.js +21 -0
  106. package/dist/role.js.map +1 -0
  107. package/dist/search.d.ts +41 -0
  108. package/dist/search.d.ts.map +1 -0
  109. package/dist/search.js +41 -0
  110. package/dist/search.js.map +1 -0
  111. package/dist/session.d.ts +92 -0
  112. package/dist/session.d.ts.map +1 -0
  113. package/dist/session.js +67 -0
  114. package/dist/session.js.map +1 -0
  115. package/dist/values.d.ts +216 -0
  116. package/dist/values.d.ts.map +1 -0
  117. package/dist/values.js +329 -0
  118. package/dist/values.js.map +1 -0
  119. package/dist/webhook.d.ts +85 -0
  120. package/dist/webhook.d.ts.map +1 -0
  121. package/dist/webhook.js +75 -0
  122. package/dist/webhook.js.map +1 -0
  123. package/dist/wire.d.ts +40 -0
  124. package/dist/wire.d.ts.map +1 -0
  125. package/dist/wire.js +40 -0
  126. package/dist/wire.js.map +1 -0
  127. package/package.json +51 -0
  128. package/src/account.ts +149 -0
  129. package/src/activity.ts +52 -0
  130. package/src/agentTask.ts +254 -0
  131. package/src/candidate.ts +83 -0
  132. package/src/company.ts +98 -0
  133. package/src/dashboard.ts +307 -0
  134. package/src/deal.ts +102 -0
  135. package/src/decision.ts +106 -0
  136. package/src/form.ts +217 -0
  137. package/src/formSubmission.ts +99 -0
  138. package/src/handbookPage.ts +99 -0
  139. package/src/importExport.ts +339 -0
  140. package/src/index.ts +324 -0
  141. package/src/invite.ts +69 -0
  142. package/src/mcpTool.ts +32 -0
  143. package/src/member.ts +53 -0
  144. package/src/moduleSetting.ts +37 -0
  145. package/src/note.ts +73 -0
  146. package/src/opportunity.ts +74 -0
  147. package/src/partnership.ts +89 -0
  148. package/src/person.ts +116 -0
  149. package/src/pipelineStage.ts +71 -0
  150. package/src/planItem.ts +91 -0
  151. package/src/position.ts +50 -0
  152. package/src/raise.ts +94 -0
  153. package/src/role.ts +45 -0
  154. package/src/search.ts +86 -0
  155. package/src/session.ts +177 -0
  156. package/src/values.ts +427 -0
  157. package/src/webhook.ts +164 -0
  158. package/src/wire.ts +51 -0
@@ -0,0 +1,91 @@
1
+ import { z } from 'zod'
2
+
3
+ import { PIPELINE_KINDS, PLAN_ITEM_STATUSES } from './values.ts'
4
+ import type { PipelineKind, PlanItemStatus } from './values.ts'
5
+ import { definedFields, idSchema, recordTimestamps } from './wire.ts'
6
+ import type { RecordTimestamps } from './wire.ts'
7
+
8
+ /**
9
+ * Wire and write shapes for `/v1/plan_items`.
10
+ *
11
+ * A plan item is a dated action on one of the four pipelines. It replaces any
12
+ * next-step text field (`brief.md`): the date, the owner, and the status are
13
+ * columns, so "what is overdue" is a query rather than a read of prose.
14
+ *
15
+ * `ownerId` is a workspace member id and is null when nobody has taken it. The
16
+ * status is never null: the table defaults it to `todo`, so a plan item always
17
+ * says where it stands.
18
+ */
19
+
20
+ export interface PlanItem extends RecordTimestamps {
21
+ readonly id: string
22
+ readonly targetType: PipelineKind
23
+ readonly targetId: string
24
+ /** `YYYY-MM-DD`, per `api.md` date-only fields. */
25
+ readonly date: string
26
+ readonly title: string
27
+ readonly ownerId: string | null
28
+ readonly status: PlanItemStatus
29
+ }
30
+
31
+ export const planItemSchema: z.ZodType<PlanItem, unknown> = z
32
+ .object({
33
+ id: idSchema,
34
+ target_type: z.enum(PIPELINE_KINDS),
35
+ target_id: idSchema,
36
+ date: z.string(),
37
+ title: z.string(),
38
+ owner_id: idSchema.nullable(),
39
+ status: z.enum(PLAN_ITEM_STATUSES),
40
+ ...recordTimestamps,
41
+ })
42
+ .transform(
43
+ (wire): PlanItem => ({
44
+ id: wire.id,
45
+ targetType: wire.target_type,
46
+ targetId: wire.target_id,
47
+ date: wire.date,
48
+ title: wire.title,
49
+ ownerId: wire.owner_id,
50
+ status: wire.status,
51
+ createdAt: wire.created_at,
52
+ updatedAt: wire.updated_at,
53
+ }),
54
+ )
55
+
56
+ export interface CreatePlanItemInput {
57
+ readonly targetType: PipelineKind
58
+ readonly targetId: string
59
+ readonly date: string
60
+ readonly title: string
61
+ readonly ownerId?: string | null
62
+ readonly status?: PlanItemStatus
63
+ }
64
+
65
+ export function createPlanItemBody(input: CreatePlanItemInput): Record<string, unknown> {
66
+ return definedFields({
67
+ target_type: input.targetType,
68
+ target_id: input.targetId,
69
+ date: input.date,
70
+ title: input.title,
71
+ owner_id: input.ownerId,
72
+ status: input.status,
73
+ })
74
+ }
75
+
76
+ /** The target never moves: re-filing a plan item under another record is a delete and a create. */
77
+ export interface PlanItemInput {
78
+ readonly date?: string
79
+ readonly title?: string
80
+ readonly ownerId?: string | null
81
+ readonly status?: PlanItemStatus
82
+ }
83
+
84
+ export function planItemBody(input: PlanItemInput): Record<string, unknown> {
85
+ return definedFields({
86
+ date: input.date,
87
+ title: input.title,
88
+ owner_id: input.ownerId,
89
+ status: input.status,
90
+ })
91
+ }
@@ -0,0 +1,50 @@
1
+ import { z } from 'zod'
2
+
3
+ import { idSchema, recordTimestamps } from './wire.ts'
4
+ import type { RecordTimestamps } from './wire.ts'
5
+
6
+ /**
7
+ * Wire and write shapes for `/v1/positions`, the Person↔Company link that holds
8
+ * the job title. Moving a link to a different person or company is a delete and
9
+ * a create, which is why only the title is updatable.
10
+ */
11
+
12
+ export interface Position extends RecordTimestamps {
13
+ readonly id: string
14
+ readonly personId: string
15
+ readonly companyId: string
16
+ readonly title: string
17
+ }
18
+
19
+ export const positionSchema: z.ZodType<Position, unknown> = z
20
+ .object({
21
+ id: idSchema,
22
+ person_id: idSchema,
23
+ company_id: idSchema,
24
+ title: z.string(),
25
+ ...recordTimestamps,
26
+ })
27
+ .transform(
28
+ (wire): Position => ({
29
+ id: wire.id,
30
+ personId: wire.person_id,
31
+ companyId: wire.company_id,
32
+ title: wire.title,
33
+ createdAt: wire.created_at,
34
+ updatedAt: wire.updated_at,
35
+ }),
36
+ )
37
+
38
+ export interface CreatePositionInput {
39
+ readonly personId: string
40
+ readonly companyId: string
41
+ readonly title: string
42
+ }
43
+
44
+ export function createPositionBody(input: CreatePositionInput): Record<string, unknown> {
45
+ return { person_id: input.personId, company_id: input.companyId, title: input.title }
46
+ }
47
+
48
+ export function updatePositionBody(title: string): Record<string, unknown> {
49
+ return { title }
50
+ }
package/src/raise.ts ADDED
@@ -0,0 +1,94 @@
1
+ import { z } from 'zod'
2
+
3
+ import { definedFields, idSchema, recordTimestamps } from './wire.ts'
4
+ import type { RecordTimestamps } from './wire.ts'
5
+
6
+ /** Wire and write shapes for `/v1/raises`. */
7
+
8
+ export interface Raise extends RecordTimestamps {
9
+ readonly id: string
10
+ readonly name: string
11
+ /** Required: the firm. The ongoing investor relationship stays a Partnership. */
12
+ readonly companyId: string
13
+ readonly stageId: string
14
+ readonly checkSizeCents: number | null
15
+ readonly currency: string | null
16
+ readonly thesisFit: string
17
+ /** Why they said no. Meaningful whenever set, not only in the passed stage. */
18
+ readonly passReason: string | null
19
+ readonly ownerId: string | null
20
+ /** `YYYY-MM-DD`, per `api.md` date-only fields. */
21
+ readonly expectedClose: string | null
22
+ readonly personIds: readonly string[]
23
+ readonly summary: string
24
+ readonly tags: readonly string[]
25
+ }
26
+
27
+ export const raiseSchema: z.ZodType<Raise, unknown> = z
28
+ .object({
29
+ id: idSchema,
30
+ name: z.string(),
31
+ company_id: idSchema,
32
+ stage_id: idSchema,
33
+ check_size_cents: z.number().int().nullable(),
34
+ currency: z.string().nullable(),
35
+ thesis_fit: z.string(),
36
+ pass_reason: z.string().nullable(),
37
+ owner_id: idSchema.nullable(),
38
+ expected_close: z.string().nullable(),
39
+ person_ids: z.array(idSchema),
40
+ summary: z.string(),
41
+ tags: z.array(z.string()),
42
+ ...recordTimestamps,
43
+ })
44
+ .transform(
45
+ (wire): Raise => ({
46
+ id: wire.id,
47
+ name: wire.name,
48
+ companyId: wire.company_id,
49
+ stageId: wire.stage_id,
50
+ checkSizeCents: wire.check_size_cents,
51
+ currency: wire.currency,
52
+ thesisFit: wire.thesis_fit,
53
+ passReason: wire.pass_reason,
54
+ ownerId: wire.owner_id,
55
+ expectedClose: wire.expected_close,
56
+ personIds: wire.person_ids,
57
+ summary: wire.summary,
58
+ tags: wire.tags,
59
+ createdAt: wire.created_at,
60
+ updatedAt: wire.updated_at,
61
+ }),
62
+ )
63
+
64
+ export interface RaiseInput {
65
+ readonly name?: string
66
+ readonly companyId?: string
67
+ readonly stageId?: string
68
+ readonly checkSizeCents?: number | null
69
+ readonly currency?: string | null
70
+ readonly thesisFit?: string
71
+ readonly passReason?: string | null
72
+ readonly ownerId?: string | null
73
+ readonly expectedClose?: string | null
74
+ readonly personIds?: readonly string[]
75
+ readonly summary?: string
76
+ readonly tags?: readonly string[]
77
+ }
78
+
79
+ export function raiseBody(input: RaiseInput): Record<string, unknown> {
80
+ return definedFields({
81
+ name: input.name,
82
+ company_id: input.companyId,
83
+ stage_id: input.stageId,
84
+ check_size_cents: input.checkSizeCents,
85
+ currency: input.currency,
86
+ thesis_fit: input.thesisFit,
87
+ pass_reason: input.passReason,
88
+ owner_id: input.ownerId,
89
+ expected_close: input.expectedClose,
90
+ person_ids: input.personIds,
91
+ summary: input.summary,
92
+ tags: input.tags,
93
+ })
94
+ }
package/src/role.ts ADDED
@@ -0,0 +1,45 @@
1
+ import { z } from 'zod'
2
+
3
+ import { ROLE_STATUSES } from './values.ts'
4
+ import type { RoleStatus } from './values.ts'
5
+ import { definedFields, idSchema, recordTimestamps } from './wire.ts'
6
+ import type { RecordTimestamps } from './wire.ts'
7
+
8
+ /**
9
+ * Wire and write shapes for `/v1/roles`, an opening the workspace is hiring for.
10
+ *
11
+ * A Role holds no people. Candidates attach through `/v1/candidates`, which is
12
+ * the Person↔Role link and the only place hiring pipeline state lives.
13
+ */
14
+
15
+ export interface Role extends RecordTimestamps {
16
+ readonly id: string
17
+ readonly title: string
18
+ readonly status: RoleStatus
19
+ }
20
+
21
+ export const roleSchema: z.ZodType<Role, unknown> = z
22
+ .object({
23
+ id: idSchema,
24
+ title: z.string(),
25
+ status: z.enum(ROLE_STATUSES),
26
+ ...recordTimestamps,
27
+ })
28
+ .transform(
29
+ (wire): Role => ({
30
+ id: wire.id,
31
+ title: wire.title,
32
+ status: wire.status,
33
+ createdAt: wire.created_at,
34
+ updatedAt: wire.updated_at,
35
+ }),
36
+ )
37
+
38
+ export interface RoleInput {
39
+ readonly title?: string
40
+ readonly status?: RoleStatus
41
+ }
42
+
43
+ export function roleBody(input: RoleInput): Record<string, unknown> {
44
+ return definedFields({ title: input.title, status: input.status })
45
+ }
package/src/search.ts ADDED
@@ -0,0 +1,86 @@
1
+ import { z } from 'zod'
2
+
3
+ import { SEARCH_COLLECTIONS } from './values.ts'
4
+ import type { SearchCollection } from './values.ts'
5
+ import { idSchema } from './wire.ts'
6
+
7
+ /**
8
+ * Wire shape for `GET /v1/search`. Read-only, so there is no body builder.
9
+ *
10
+ * One object rather than a list envelope, and no cursor. Nine collections are
11
+ * ranked separately, because a `ts_rank` over a handbook page and one over a
12
+ * three-word Role title are not comparable numbers, and "which Deal" and "which
13
+ * handbook page" are different questions anyway.
14
+ *
15
+ * Every group carries `total`, the count of every match, beside `items`, which
16
+ * holds however many the request's `?limit=` allowed.
17
+ */
18
+
19
+ export interface SearchResult {
20
+ readonly id: string
21
+ readonly title: string
22
+ /**
23
+ * The record's one line of context, already resolved. What it holds depends on
24
+ * the collection: an email for a Person, a domain for a Company, the stage
25
+ * label for a Deal or Raise, the kind for an Opportunity or Partnership, the
26
+ * status for a Role, the slug for a handbook page, and the date decided for a
27
+ * Decision as `YYYY-MM-DD`.
28
+ */
29
+ readonly subtitle: string | null
30
+ /** A fragment of the record's prose centred on the match. Empty when it has none. */
31
+ readonly snippet: string
32
+ }
33
+
34
+ export interface SearchResultGroup {
35
+ readonly collection: SearchCollection
36
+ readonly total: number
37
+ readonly items: readonly SearchResult[]
38
+ }
39
+
40
+ export interface SearchResults {
41
+ readonly query: string
42
+ readonly limit: number
43
+ /** Across every group, which is what a "12 results" heading is built from. */
44
+ readonly total: number
45
+ readonly groups: readonly SearchResultGroup[]
46
+ }
47
+
48
+ const resultSchema: z.ZodType<SearchResult, unknown> = z
49
+ .object({
50
+ id: idSchema,
51
+ title: z.string(),
52
+ subtitle: z.string().nullable(),
53
+ snippet: z.string(),
54
+ })
55
+ .transform((wire) => ({
56
+ id: wire.id,
57
+ title: wire.title,
58
+ subtitle: wire.subtitle,
59
+ snippet: wire.snippet,
60
+ }))
61
+
62
+ const groupSchema: z.ZodType<SearchResultGroup, unknown> = z
63
+ .object({
64
+ type: z.enum(SEARCH_COLLECTIONS),
65
+ total: z.number().int(),
66
+ items: z.array(resultSchema),
67
+ })
68
+ .transform((wire) => ({
69
+ collection: wire.type,
70
+ total: wire.total,
71
+ items: wire.items,
72
+ }))
73
+
74
+ export const searchResultsSchema: z.ZodType<SearchResults, unknown> = z
75
+ .object({
76
+ query: z.string(),
77
+ limit: z.number().int(),
78
+ total: z.number().int(),
79
+ groups: z.array(groupSchema),
80
+ })
81
+ .transform((wire) => ({
82
+ query: wire.query,
83
+ limit: wire.limit,
84
+ total: wire.total,
85
+ groups: wire.groups,
86
+ }))
package/src/session.ts ADDED
@@ -0,0 +1,177 @@
1
+ import { z } from 'zod'
2
+
3
+ import type { Account } from './account.ts'
4
+ import { MEMBER_ROLES } from './values.ts'
5
+ import type { MemberRole } from './values.ts'
6
+ import { definedFields, idSchema } from './wire.ts'
7
+
8
+ /**
9
+ * Wire shapes for `/v1/auth/*` and `/v1/workspaces`: how a browser gets a
10
+ * session, and which workspace that session is in.
11
+ *
12
+ * `workspaceId` is nullable because signup creates an account and nothing else.
13
+ * Every CRM endpoint answers `403` until a workspace exists, so the shell has to
14
+ * be able to tell "signed out" from "signed in, no workspace yet".
15
+ *
16
+ * The password-reset pair belongs here rather than in `account.ts` for the same
17
+ * reason sign-in does: a caller running them has no account context yet. What
18
+ * `account.ts` holds is the signed-in person.
19
+ */
20
+
21
+ export interface Session {
22
+ readonly userId: string
23
+ readonly sessionId: string
24
+ readonly workspaceId: string | null
25
+ readonly role: MemberRole | null
26
+ }
27
+
28
+ export const sessionSchema: z.ZodType<Session, unknown> = z
29
+ .object({
30
+ user_id: idSchema,
31
+ session_id: idSchema,
32
+ workspace_id: idSchema.nullable(),
33
+ role: z.enum(MEMBER_ROLES).nullable(),
34
+ })
35
+ .transform(
36
+ (wire): Session => ({
37
+ userId: wire.user_id,
38
+ sessionId: wire.session_id,
39
+ workspaceId: wire.workspace_id,
40
+ role: wire.role,
41
+ }),
42
+ )
43
+
44
+ /** What `POST /v1/auth/login` and `/v1/auth/signup` answer with. */
45
+ export interface SignedInAccount {
46
+ readonly account: Account
47
+ readonly activeWorkspaceId: string | null
48
+ }
49
+
50
+ export const signedInAccountSchema: z.ZodType<SignedInAccount, unknown> = z
51
+ .object({
52
+ account: z.object({ id: idSchema, email: z.string(), name: z.string() }),
53
+ active_workspace_id: idSchema.nullable(),
54
+ })
55
+ .transform(
56
+ (wire): SignedInAccount => ({
57
+ account: wire.account,
58
+ activeWorkspaceId: wire.active_workspace_id,
59
+ }),
60
+ )
61
+
62
+ export interface Workspace {
63
+ readonly id: string
64
+ readonly name: string
65
+ readonly slug: string
66
+ readonly timezone: string
67
+ readonly tagline: string | null
68
+ readonly oneLiner: string | null
69
+ }
70
+
71
+ export const workspaceSchema: z.ZodType<Workspace, unknown> = z
72
+ .object({
73
+ id: idSchema,
74
+ name: z.string(),
75
+ slug: z.string(),
76
+ timezone: z.string(),
77
+ tagline: z.string().nullable(),
78
+ one_liner: z.string().nullable(),
79
+ })
80
+ .transform(
81
+ (wire): Workspace => ({
82
+ id: wire.id,
83
+ name: wire.name,
84
+ slug: wire.slug,
85
+ timezone: wire.timezone,
86
+ tagline: wire.tagline,
87
+ oneLiner: wire.one_liner,
88
+ }),
89
+ )
90
+
91
+ export interface CreateWorkspaceInput {
92
+ readonly name: string
93
+ readonly slug: string
94
+ readonly timezone: string
95
+ }
96
+
97
+ export function createWorkspaceBody(input: CreateWorkspaceInput): Record<string, unknown> {
98
+ return { name: input.name, slug: input.slug, timezone: input.timezone }
99
+ }
100
+
101
+ /**
102
+ * Settings a workspace admin can change.
103
+ *
104
+ * `tagline` and `oneLiner` are the two strings an agent reads to say who this
105
+ * company is, so `null` clears them and `undefined` leaves them alone, per
106
+ * `api.md`. `definedFields` is what keeps those two apart on the wire.
107
+ */
108
+ export interface UpdateWorkspaceInput {
109
+ readonly name?: string
110
+ readonly slug?: string
111
+ readonly timezone?: string
112
+ readonly tagline?: string | null
113
+ readonly oneLiner?: string | null
114
+ }
115
+
116
+ export function updateWorkspaceBody(input: UpdateWorkspaceInput): Record<string, unknown> {
117
+ return definedFields({
118
+ name: input.name,
119
+ slug: input.slug,
120
+ timezone: input.timezone,
121
+ tagline: input.tagline,
122
+ one_liner: input.oneLiner,
123
+ })
124
+ }
125
+
126
+ export interface LogInInput {
127
+ readonly email: string
128
+ readonly password: string
129
+ }
130
+
131
+ export function logInBody(input: LogInInput): Record<string, unknown> {
132
+ return { email: input.email, password: input.password }
133
+ }
134
+
135
+ /**
136
+ * Creating an account. It answers the same shape sign-in does, with
137
+ * `activeWorkspaceId` null: signup makes the user and stops there.
138
+ */
139
+ export interface SignUpInput {
140
+ readonly name: string
141
+ readonly email: string
142
+ readonly password: string
143
+ }
144
+
145
+ export function signUpBody(input: SignUpInput): Record<string, unknown> {
146
+ return { name: input.name, email: input.email, password: input.password }
147
+ }
148
+
149
+ /**
150
+ * Asking for a reset link.
151
+ *
152
+ * `resetUrlTemplate` carries the literal `{token}`, which the email replaces.
153
+ * The caller supplies it for the same reason an invitation does: the service
154
+ * sends the mail and has no idea what address the browser reached it at.
155
+ */
156
+ export interface RequestPasswordResetInput {
157
+ readonly email: string
158
+ readonly resetUrlTemplate: string
159
+ }
160
+
161
+ export function requestPasswordResetBody(
162
+ input: RequestPasswordResetInput,
163
+ ): Record<string, unknown> {
164
+ return { email: input.email, reset_url_template: input.resetUrlTemplate }
165
+ }
166
+
167
+ /** Spending the token from that email. Answers `204`; it does not sign anyone in. */
168
+ export interface ConfirmPasswordResetInput {
169
+ readonly token: string
170
+ readonly password: string
171
+ }
172
+
173
+ export function confirmPasswordResetBody(
174
+ input: ConfirmPasswordResetInput,
175
+ ): Record<string, unknown> {
176
+ return { token: input.token, password: input.password }
177
+ }