@kelpie/schemas 0.11.0 → 0.13.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 (95) hide show
  1. package/dist/account.d.ts +5 -0
  2. package/dist/account.d.ts.map +1 -1
  3. package/dist/account.js +2 -0
  4. package/dist/account.js.map +1 -1
  5. package/dist/address.d.ts +55 -0
  6. package/dist/address.d.ts.map +1 -0
  7. package/dist/address.js +210 -0
  8. package/dist/address.js.map +1 -0
  9. package/dist/apiKeyScopes.d.ts +3 -3
  10. package/dist/apiKeyScopes.d.ts.map +1 -1
  11. package/dist/apiKeyScopes.js +6 -0
  12. package/dist/apiKeyScopes.js.map +1 -1
  13. package/dist/attendance.d.ts +33 -0
  14. package/dist/attendance.d.ts.map +1 -0
  15. package/dist/attendance.js +35 -0
  16. package/dist/attendance.js.map +1 -0
  17. package/dist/company.d.ts +3 -4
  18. package/dist/company.d.ts.map +1 -1
  19. package/dist/company.js +4 -6
  20. package/dist/company.js.map +1 -1
  21. package/dist/countries.d.ts +30 -0
  22. package/dist/countries.d.ts.map +1 -0
  23. package/dist/countries.js +300 -0
  24. package/dist/countries.js.map +1 -0
  25. package/dist/dashboard.d.ts +11 -0
  26. package/dist/dashboard.d.ts.map +1 -1
  27. package/dist/dashboard.js +23 -0
  28. package/dist/dashboard.js.map +1 -1
  29. package/dist/event.d.ts +54 -0
  30. package/dist/event.d.ts.map +1 -0
  31. package/dist/event.js +85 -0
  32. package/dist/event.js.map +1 -0
  33. package/dist/eventAssociation.d.ts +17 -0
  34. package/dist/eventAssociation.d.ts.map +1 -0
  35. package/dist/eventAssociation.js +17 -0
  36. package/dist/eventAssociation.js.map +1 -0
  37. package/dist/form.d.ts +5 -5
  38. package/dist/form.d.ts.map +1 -1
  39. package/dist/form.js +2 -2
  40. package/dist/form.js.map +1 -1
  41. package/dist/formMapTargets.d.ts +1 -1
  42. package/dist/formMapTargets.d.ts.map +1 -1
  43. package/dist/formMapTargets.js +41 -5
  44. package/dist/formMapTargets.js.map +1 -1
  45. package/dist/importExport.d.ts.map +1 -1
  46. package/dist/importExport.js +3 -3
  47. package/dist/importExport.js.map +1 -1
  48. package/dist/index.d.ts +17 -7
  49. package/dist/index.d.ts.map +1 -1
  50. package/dist/index.js +8 -3
  51. package/dist/index.js.map +1 -1
  52. package/dist/person.d.ts +3 -2
  53. package/dist/person.d.ts.map +1 -1
  54. package/dist/person.js +4 -3
  55. package/dist/person.js.map +1 -1
  56. package/dist/planItem.d.ts +4 -4
  57. package/dist/planItem.d.ts.map +1 -1
  58. package/dist/planItem.js +2 -2
  59. package/dist/planItem.js.map +1 -1
  60. package/dist/publicConfig.d.ts +42 -3
  61. package/dist/publicConfig.d.ts.map +1 -1
  62. package/dist/publicConfig.js +20 -0
  63. package/dist/publicConfig.js.map +1 -1
  64. package/dist/sampleData.d.ts +7 -2
  65. package/dist/sampleData.d.ts.map +1 -1
  66. package/dist/sampleData.js +4 -0
  67. package/dist/sampleData.js.map +1 -1
  68. package/dist/session.d.ts +28 -0
  69. package/dist/session.d.ts.map +1 -1
  70. package/dist/session.js +39 -0
  71. package/dist/session.js.map +1 -1
  72. package/dist/values.d.ts +35 -5
  73. package/dist/values.d.ts.map +1 -1
  74. package/dist/values.js +90 -0
  75. package/dist/values.js.map +1 -1
  76. package/package.json +1 -1
  77. package/src/account.ts +7 -0
  78. package/src/address.ts +287 -0
  79. package/src/apiKeyScopes.ts +6 -0
  80. package/src/attendance.ts +72 -0
  81. package/src/company.ts +7 -10
  82. package/src/countries.ts +320 -0
  83. package/src/dashboard.ts +36 -0
  84. package/src/event.ts +159 -0
  85. package/src/eventAssociation.ts +36 -0
  86. package/src/form.ts +7 -7
  87. package/src/formMapTargets.ts +43 -4
  88. package/src/importExport.ts +3 -3
  89. package/src/index.ts +80 -2
  90. package/src/person.ts +7 -5
  91. package/src/planItem.ts +6 -6
  92. package/src/publicConfig.ts +44 -3
  93. package/src/sampleData.ts +11 -2
  94. package/src/session.ts +76 -0
  95. package/src/values.ts +119 -0
@@ -1,9 +1,12 @@
1
1
  import type { CustomFieldObjectType, CustomFieldType, FormFieldType } from './values.ts'
2
+ import { COMPANY_ADDRESS_KINDS, PERSON_ADDRESS_KINDS } from './address.ts'
2
3
  import {
3
4
  ACCOUNT_TYPES,
4
5
  COMPANY_STAGES,
5
6
  CUSTOM_FIELD_OBJECT_TYPE_LABELS,
6
7
  CUSTOM_FIELD_TYPE_LABELS,
8
+ EVENT_FORMATS,
9
+ EVENT_STATUSES,
7
10
  FORM_FIELD_MAP_TARGET_LABELS,
8
11
  ICP_FITS,
9
12
  INFLUENCE_LEVELS,
@@ -33,6 +36,7 @@ export const FORM_MAP_OBJECT_TYPES = [
33
36
  'partnership',
34
37
  'enquiry',
35
38
  'raise',
39
+ 'event',
36
40
  ] as const
37
41
 
38
42
  export type FormMapObjectType = (typeof FORM_MAP_OBJECT_TYPES)[number]
@@ -46,6 +50,7 @@ export const FORM_MAP_OBJECT_TYPE_LABELS: Readonly<Record<FormMapObjectType, str
46
50
  partnership: 'Partnership',
47
51
  enquiry: 'Enquiry',
48
52
  raise: 'Raise',
53
+ event: 'Event',
49
54
  }
50
55
 
51
56
  /** The value shape a mapped target expects from a submit answer. */
@@ -98,7 +103,18 @@ const PERSON_STANDARD_FIELDS: readonly FormMapStandardField[] = [
98
103
  { field: 'email', label: 'email', valueType: 'email' },
99
104
  { field: 'phones', label: 'phone', valueType: 'phones' },
100
105
  { field: 'timezone', label: 'timezone', valueType: 'text' },
101
- { field: 'location', label: 'location', valueType: 'text' },
106
+ {
107
+ field: 'address.kind',
108
+ label: 'address kind',
109
+ valueType: 'enum',
110
+ enumValues: PERSON_ADDRESS_KINDS,
111
+ },
112
+ { field: 'address.line1', label: 'address line 1', valueType: 'text' },
113
+ { field: 'address.line2', label: 'address line 2', valueType: 'text' },
114
+ { field: 'address.city', label: 'address city', valueType: 'text' },
115
+ { field: 'address.region', label: 'address region', valueType: 'text' },
116
+ { field: 'address.postal_code', label: 'address postal code', valueType: 'text' },
117
+ { field: 'address.country', label: 'address country', valueType: 'text' },
102
118
  {
103
119
  field: 'preferred_channel',
104
120
  label: 'preferred channel',
@@ -139,8 +155,18 @@ const COMPANY_STANDARD_FIELDS: readonly FormMapStandardField[] = [
139
155
  valueType: 'enum',
140
156
  enumValues: SIZE_BANDS,
141
157
  },
142
- { field: 'hq', label: 'hq', valueType: 'text' },
143
- { field: 'website', label: 'website', valueType: 'url' },
158
+ {
159
+ field: 'address.kind',
160
+ label: 'address kind',
161
+ valueType: 'enum',
162
+ enumValues: COMPANY_ADDRESS_KINDS,
163
+ },
164
+ { field: 'address.line1', label: 'address line 1', valueType: 'text' },
165
+ { field: 'address.line2', label: 'address line 2', valueType: 'text' },
166
+ { field: 'address.city', label: 'address city', valueType: 'text' },
167
+ { field: 'address.region', label: 'address region', valueType: 'text' },
168
+ { field: 'address.postal_code', label: 'address postal code', valueType: 'text' },
169
+ { field: 'address.country', label: 'address country', valueType: 'text' },
144
170
  {
145
171
  field: 'account_type',
146
172
  label: 'account type',
@@ -211,6 +237,18 @@ const RAISE_STANDARD_FIELDS: readonly FormMapStandardField[] = [
211
237
  { field: 'tags', label: 'tags', valueType: 'tags' },
212
238
  ]
213
239
 
240
+ const EVENT_STANDARD_FIELDS: readonly FormMapStandardField[] = [
241
+ { field: 'name', label: 'name', valueType: 'text' },
242
+ { field: 'kind', label: 'kind', valueType: 'text' },
243
+ { field: 'location', label: 'location', valueType: 'text' },
244
+ { field: 'meeting_url', label: 'meeting URL', valueType: 'url' },
245
+ { field: 'format', label: 'format', valueType: 'enum', enumValues: EVENT_FORMATS },
246
+ { field: 'details', label: 'details', valueType: 'long_text' },
247
+ { field: 'status', label: 'status', valueType: 'enum', enumValues: EVENT_STATUSES },
248
+ { field: 'summary', label: 'summary', valueType: 'long_text' },
249
+ { field: 'tags', label: 'tags', valueType: 'tags' },
250
+ ]
251
+
214
252
  /** Standard writable fields per object type, keyed by object. */
215
253
  export const FORM_STANDARD_MAP_FIELDS: Readonly<
216
254
  Record<FormMapObjectType, readonly FormMapStandardField[]>
@@ -223,6 +261,7 @@ export const FORM_STANDARD_MAP_FIELDS: Readonly<
223
261
  partnership: PARTNERSHIP_STANDARD_FIELDS,
224
262
  enquiry: ENQUIRY_STANDARD_FIELDS,
225
263
  raise: RAISE_STANDARD_FIELDS,
264
+ event: EVENT_STANDARD_FIELDS,
226
265
  }
227
266
 
228
267
  function standardFieldTarget(objectType: FormMapObjectType, field: FormMapStandardField): string {
@@ -343,7 +382,7 @@ export function parseFormMapTarget(target: string): ParsedFormMapTarget | undefi
343
382
  }
344
383
  }
345
384
 
346
- const standardMatch = /^([a-z_]+)\.([a-z_]+)$/.exec(target)
385
+ const standardMatch = /^([a-z_]+)\.([a-z][a-z0-9_.]*)$/.exec(target)
347
386
 
348
387
  if (standardMatch === null) {
349
388
  return undefined
@@ -1,5 +1,6 @@
1
1
  import { z } from 'zod'
2
2
 
3
+ import { addressCsvColumns, COMPANY_ADDRESS_KINDS, PERSON_ADDRESS_KINDS } from './address.ts'
3
4
  import type { CustomFieldObjectType, PipelineKind } from './values.ts'
4
5
  import { idSchema, recordTimestamps } from './wire.ts'
5
6
  import type { RecordTimestamps } from './wire.ts'
@@ -180,8 +181,7 @@ export const OBJECT_COLUMNS: Readonly<Record<ImportObject, readonly CsvColumn[]>
180
181
  { key: 'description', label: 'Description', required: false },
181
182
  { key: 'summary', label: 'Summary', required: false },
182
183
  { key: 'tags', label: 'Tags', required: false },
183
- { key: 'website', label: 'Website', required: false },
184
- { key: 'hq', label: 'HQ', required: false },
184
+ ...addressCsvColumns(COMPANY_ADDRESS_KINDS),
185
185
  ],
186
186
  people: [
187
187
  { key: 'name', label: 'Name', required: false },
@@ -191,7 +191,7 @@ export const OBJECT_COLUMNS: Readonly<Record<ImportObject, readonly CsvColumn[]>
191
191
  { key: 'suffix', label: 'Suffix', required: false },
192
192
  { key: 'email', label: 'Email', required: true },
193
193
  { key: 'timezone', label: 'Timezone', required: false },
194
- { key: 'location', label: 'Location', required: false },
194
+ ...addressCsvColumns(PERSON_ADDRESS_KINDS),
195
195
  { key: 'preferred_channel', label: 'Preferred channel', required: false },
196
196
  { key: 'influence', label: 'Influence', required: false },
197
197
  { key: 'relationship', label: 'Relationship', required: false },
package/src/index.ts CHANGED
@@ -21,6 +21,10 @@ export {
21
21
  AGENT_TASK_PLACEMENTS,
22
22
  AGENT_TASK_TARGET_TYPES,
23
23
  API_KEY_KINDS,
24
+ ATTENDANCE_SOURCE_LABELS,
25
+ ATTENDANCE_SOURCES,
26
+ ATTENDANCE_STATUS_LABELS,
27
+ ATTENDANCE_STATUSES,
24
28
  CANDIDATE_STATUS_LABELS,
25
29
  CANDIDATE_STATUSES,
26
30
  COMPANY_STAGES,
@@ -34,9 +38,16 @@ export {
34
38
  CUSTOM_FIELD_TYPE_LABELS,
35
39
  CUSTOM_FIELD_TYPES,
36
40
  CUSTOM_FIELD_TYPES_WITH_OPTIONS,
41
+ EVENT_ASSOCIATION_TARGET_TYPE_LABELS,
42
+ EVENT_ASSOCIATION_TARGET_TYPES,
43
+ EVENT_FORMAT_LABELS,
44
+ EVENT_FORMATS,
45
+ EVENT_STATUS_LABELS,
46
+ EVENT_STATUSES,
37
47
  EXTENSIBLE_RECORD_TYPES,
38
48
  FIRST_INTERVIEW_STAGE,
39
49
  FORM_ACTION_STATUSES,
50
+ FORM_ATTACH_TARGET_TYPES,
40
51
  FORM_BOOLEAN_FIELD_TYPES,
41
52
  FORM_FIELD_MAP_TARGET_LABELS,
42
53
  FORM_FIELD_MAP_TARGETS,
@@ -58,6 +69,8 @@ export {
58
69
  PIPELINE_KINDS,
59
70
  PLAN_ITEM_STATUS_LABELS,
60
71
  PLAN_ITEM_STATUSES,
72
+ PLAN_ITEM_TARGET_TYPE_LABELS,
73
+ PLAN_ITEM_TARGET_TYPES,
61
74
  PREFERRED_CHANNELS,
62
75
  RECORD_TARGET_TYPE_LABELS,
63
76
  RECORD_TARGET_TYPES,
@@ -82,6 +95,8 @@ export type {
82
95
  AgentTaskPlacement,
83
96
  AgentTaskTargetType,
84
97
  ApiKeyKind,
98
+ AttendanceSource,
99
+ AttendanceStatus,
85
100
  CandidateStatus,
86
101
  CompanyStage,
87
102
  ConsentPurposeStatus,
@@ -90,8 +105,12 @@ export type {
90
105
  CustomFieldObjectType,
91
106
  CustomFieldType,
92
107
  CustomFieldTypeWithOptions,
108
+ EventAssociationTargetType,
109
+ EventFormat,
110
+ EventStatus,
93
111
  ExtensibleRecordType,
94
112
  FormActionStatus,
113
+ FormAttachTargetType,
95
114
  FormBooleanFieldType,
96
115
  FormFieldMapTarget,
97
116
  FormFieldType,
@@ -105,6 +124,7 @@ export type {
105
124
  MemberRole,
106
125
  PipelineKind,
107
126
  PlanItemStatus,
127
+ PlanItemTargetType,
108
128
  PreferredChannel,
109
129
  RecordTargetType,
110
130
  Relationship,
@@ -164,6 +184,44 @@ export type { EventActor, EventTarget, KelpieEvent, UpdateEventData } from './ev
164
184
 
165
185
  export { composeName } from './names.ts'
166
186
  export type { NameParts } from './names.ts'
187
+
188
+ export {
189
+ COUNTRIES,
190
+ COUNTRY_CODES,
191
+ countryName,
192
+ isCountryCode,
193
+ normaliseCountry,
194
+ } from './countries.ts'
195
+ export type { Country } from './countries.ts'
196
+
197
+ export {
198
+ ADDRESS_PARTS,
199
+ COMPANY_ADDRESS_KINDS,
200
+ COMPANY_ADDRESS_KIND_LABELS,
201
+ PERSON_ADDRESS_KINDS,
202
+ PERSON_ADDRESS_KIND_LABELS,
203
+ addressBody,
204
+ addressColumnKey,
205
+ addressColumnLabel,
206
+ addressCsvColumns,
207
+ companyAddressColumnKeys,
208
+ companyAddressSchema,
209
+ companyAddressesSchema,
210
+ formatAddress,
211
+ personAddressColumnKeys,
212
+ personAddressSchema,
213
+ personAddressesSchema,
214
+ primaryAddress,
215
+ } from './address.ts'
216
+ export type {
217
+ AddressPart,
218
+ CompanyAddress,
219
+ CompanyAddressKind,
220
+ PersonAddress,
221
+ PersonAddressKind,
222
+ PostalAddress,
223
+ } from './address.ts'
224
+
167
225
  export { personBody, personSchema } from './person.ts'
168
226
  export type { Person, PersonInput, SocialProfile } from './person.ts'
169
227
 
@@ -205,6 +263,15 @@ export type { Role, RoleInput } from './role.ts'
205
263
  export { candidateBody, candidateSchema, createCandidateBody } from './candidate.ts'
206
264
  export type { Candidate, CandidateInput, CreateCandidateInput } from './candidate.ts'
207
265
 
266
+ export { attendanceBody, attendanceSchema, createAttendanceBody } from './attendance.ts'
267
+ export type { Attendance, AttendanceInput, CreateAttendanceInput } from './attendance.ts'
268
+
269
+ export { createEventBody, eventBody, eventSchema } from './event.ts'
270
+ export type { CreateEventInput, Event, EventAssociation, EventInput } from './event.ts'
271
+
272
+ export { eventAssociationRowSchema } from './eventAssociation.ts'
273
+ export type { EventAssociationRow } from './eventAssociation.ts'
274
+
208
275
  export {
209
276
  createPipelineStageBody,
210
277
  pipelineStageSchema,
@@ -419,6 +486,7 @@ export type {
419
486
  DashboardSignal,
420
487
  DashboardStaleContact,
421
488
  DashboardTouchpoint,
489
+ DashboardUpcomingEvent,
422
490
  TargetRef,
423
491
  } from './dashboard.ts'
424
492
 
@@ -442,26 +510,36 @@ export { createInviteBody, inviteSchema } from './invite.ts'
442
510
  export type { CreateInviteInput, Invite } from './invite.ts'
443
511
 
444
512
  export {
513
+ accountWorkspaceSchema,
445
514
  confirmEmailVerificationBody,
446
515
  confirmPasswordResetBody,
447
516
  createWorkspaceBody,
517
+ HANDBOOK_TEMPLATE_IDS,
448
518
  logInBody,
449
519
  requestPasswordResetBody,
520
+ seedHandbookBody,
521
+ seedHandbookResultSchema,
450
522
  sessionSchema,
451
523
  signUpBody,
452
524
  signedInAccountSchema,
525
+ switchWorkspaceBody,
453
526
  updateWorkspaceBody,
454
527
  workspaceSchema,
455
528
  } from './session.ts'
456
529
  export type {
530
+ AccountWorkspace,
457
531
  ConfirmEmailVerificationInput,
458
532
  ConfirmPasswordResetInput,
459
533
  CreateWorkspaceInput,
534
+ HandbookTemplateId,
460
535
  LogInInput,
461
536
  RequestPasswordResetInput,
537
+ SeedHandbookInput,
538
+ SeedHandbookResult,
462
539
  Session,
463
540
  SignUpInput,
464
541
  SignedInAccount,
542
+ SwitchWorkspaceInput,
465
543
  UpdateWorkspaceInput,
466
544
  Workspace,
467
545
  } from './session.ts'
@@ -486,5 +564,5 @@ export type {
486
564
  UpdateAccountPreferencesInput,
487
565
  } from './account.ts'
488
566
 
489
- export { publicConfigSchema } from './publicConfig.ts'
490
- export type { PublicConfig, PublicRuntimeMode } from './publicConfig.ts'
567
+ export { isHttpOrigin, publicConfigSchema, publicRegionSchema, publicRegionsSchema } from './publicConfig.ts'
568
+ export type { PublicConfig, PublicRegion, PublicRuntimeMode } from './publicConfig.ts'
package/src/person.ts CHANGED
@@ -5,6 +5,8 @@ import {
5
5
  customFieldValuesSchema,
6
6
  } from './customField.ts'
7
7
  import type { CustomFieldValue, CustomFieldValues } from './customField.ts'
8
+ import { addressBody, personAddressesSchema } from './address.ts'
9
+ import type { PersonAddress } from './address.ts'
8
10
  import { personConsentSchema, personConsentWriteBody } from './personConsent.ts'
9
11
  import type { PersonConsent, PersonConsentInput } from './personConsent.ts'
10
12
  import {
@@ -43,7 +45,7 @@ export interface Person extends RecordTimestamps {
43
45
  readonly phones: readonly string[]
44
46
  readonly socialProfiles: readonly SocialProfile[]
45
47
  readonly timezone: string | null
46
- readonly location: string | null
48
+ readonly addresses: readonly PersonAddress[]
47
49
  readonly preferredChannel: PreferredChannel
48
50
  readonly influence: Influence
49
51
  readonly relationship: Relationship
@@ -79,7 +81,7 @@ export const personSchema: z.ZodType<Person, unknown> = z
79
81
  phones: z.array(z.string()),
80
82
  social_profiles: z.array(socialProfileSchema),
81
83
  timezone: z.string().nullable(),
82
- location: z.string().nullable(),
84
+ addresses: personAddressesSchema,
83
85
  preferred_channel: z.enum(PREFERRED_CHANNELS),
84
86
  influence: z.enum(INFLUENCE_LEVELS),
85
87
  relationship: z.enum(RELATIONSHIP_LEVELS),
@@ -103,7 +105,7 @@ export const personSchema: z.ZodType<Person, unknown> = z
103
105
  phones: wire.phones,
104
106
  socialProfiles: wire.social_profiles,
105
107
  timezone: wire.timezone,
106
- location: wire.location,
108
+ addresses: wire.addresses,
107
109
  preferredChannel: wire.preferred_channel,
108
110
  influence: wire.influence,
109
111
  relationship: wire.relationship,
@@ -134,7 +136,7 @@ export interface PersonInput {
134
136
  readonly phones?: readonly string[]
135
137
  readonly socialProfiles?: readonly SocialProfile[]
136
138
  readonly timezone?: string | null
137
- readonly location?: string | null
139
+ readonly addresses?: readonly PersonAddress[]
138
140
  readonly preferredChannel?: PreferredChannel
139
141
  readonly influence?: Influence
140
142
  readonly relationship?: Relationship
@@ -166,7 +168,7 @@ export function personBody(input: PersonInput): Record<string, unknown> {
166
168
  phones: input.phones,
167
169
  social_profiles: input.socialProfiles,
168
170
  timezone: input.timezone,
169
- location: input.location,
171
+ addresses: input.addresses?.map(addressBody),
170
172
  preferred_channel: input.preferredChannel,
171
173
  influence: input.influence,
172
174
  relationship: input.relationship,
package/src/planItem.ts CHANGED
@@ -1,14 +1,14 @@
1
1
  import { z } from 'zod'
2
2
 
3
- import { PIPELINE_KINDS, PLAN_ITEM_STATUSES } from './values.ts'
4
- import type { PipelineKind, PlanItemStatus } from './values.ts'
3
+ import { PLAN_ITEM_STATUSES, PLAN_ITEM_TARGET_TYPES } from './values.ts'
4
+ import type { PlanItemStatus, PlanItemTargetType } from './values.ts'
5
5
  import { definedFields, idSchema, recordTimestamps } from './wire.ts'
6
6
  import type { RecordTimestamps } from './wire.ts'
7
7
 
8
8
  /**
9
9
  * Wire and write shapes for `/v1/plan_items`.
10
10
  *
11
- * A plan item is a dated action on one of the four pipelines. It replaces any
11
+ * A plan item is a dated action on a pipeline record or an Event. It replaces any
12
12
  * next-step text field (`brief.md`): the date, the owner, and the status are
13
13
  * columns, so "what is overdue" is a query rather than a read of prose.
14
14
  *
@@ -19,7 +19,7 @@ import type { RecordTimestamps } from './wire.ts'
19
19
 
20
20
  export interface PlanItem extends RecordTimestamps {
21
21
  readonly id: string
22
- readonly targetType: PipelineKind
22
+ readonly targetType: PlanItemTargetType
23
23
  readonly targetId: string
24
24
  /** `YYYY-MM-DD`, per `api.md` date-only fields. */
25
25
  readonly date: string
@@ -31,7 +31,7 @@ export interface PlanItem extends RecordTimestamps {
31
31
  export const planItemSchema: z.ZodType<PlanItem, unknown> = z
32
32
  .object({
33
33
  id: idSchema,
34
- target_type: z.enum(PIPELINE_KINDS),
34
+ target_type: z.enum(PLAN_ITEM_TARGET_TYPES),
35
35
  target_id: idSchema,
36
36
  date: z.string(),
37
37
  title: z.string(),
@@ -54,7 +54,7 @@ export const planItemSchema: z.ZodType<PlanItem, unknown> = z
54
54
  )
55
55
 
56
56
  export interface CreatePlanItemInput {
57
- readonly targetType: PipelineKind
57
+ readonly targetType: PlanItemTargetType
58
58
  readonly targetId: string
59
59
  readonly date: string
60
60
  readonly title: string
@@ -5,27 +5,68 @@ import { z } from 'zod'
5
5
  *
6
6
  * A public, credential-free endpoint the browser reads once at boot. It names
7
7
  * which runtime the server is in, and the human-readable name of this
8
- * deployment. The UI uses `runtimeMode` to gate a non-production banner and
9
- * `siteName` to label it. Nothing here is sensitive: `runtimeMode` is
10
- * observable from any error message, and `siteName` exists to be visible.
8
+ * deployment. The UI uses `runtimeMode` to gate a non-production banner,
9
+ * `siteName` to label it, `signupsEnabled` to show or hide the sign-up form,
10
+ * and `regions` to draw a region switcher on signed-out pages. Nothing here
11
+ * is sensitive: `runtimeMode` is observable from any error message, and the
12
+ * other fields exist to be visible.
11
13
  */
12
14
 
13
15
  export type PublicRuntimeMode = 'development' | 'test' | 'production'
14
16
 
17
+ /**
18
+ * One deployable origin a multi-region assembly advertises on the sign-in
19
+ * page. `origin` is the host the browser navigates to; the path and query
20
+ * stay. An empty list (the default) means a single-origin install.
21
+ */
22
+ export interface PublicRegion {
23
+ readonly id: string
24
+ readonly label: string
25
+ readonly origin: string
26
+ }
27
+
15
28
  export interface PublicConfig {
16
29
  readonly runtimeMode: PublicRuntimeMode
17
30
  /** Undefined when the assembly did not set `KELPIE_SITE_NAME`. */
18
31
  readonly siteName: string | null
32
+ /** False when the instance has closed new-account creation (`SIGNUPS=closed`). */
33
+ readonly signupsEnabled: boolean
34
+ /** Empty when the assembly did not declare regions. Two or more draws a switcher. */
35
+ readonly regions: readonly PublicRegion[]
19
36
  }
20
37
 
38
+ /**
39
+ * True when `value` is an absolute `http:` or `https:` origin, with no path
40
+ * or query. The switcher concatenates this with the current path, so a path
41
+ * on the origin would double up. Written as a pattern rather than `new URL`
42
+ * so this package does not take a DOM lib.
43
+ */
44
+ const HTTP_ORIGIN = /^https?:\/\/[^/?#]+$/u
45
+
46
+ export function isHttpOrigin(value: string): boolean {
47
+ return HTTP_ORIGIN.test(value)
48
+ }
49
+
50
+ export const publicRegionSchema = z.strictObject({
51
+ id: z.string().min(1),
52
+ label: z.string().min(1),
53
+ origin: z.string().refine(isHttpOrigin, { message: 'must be an absolute http or https origin' }),
54
+ })
55
+
56
+ export const publicRegionsSchema = z.array(publicRegionSchema)
57
+
21
58
  export const publicConfigSchema = z
22
59
  .strictObject({
23
60
  runtime_mode: z.enum(['development', 'test', 'production']),
24
61
  site_name: z.string().min(1).nullable(),
62
+ signups_enabled: z.boolean(),
63
+ regions: publicRegionsSchema.optional().default([]),
25
64
  })
26
65
  .transform(
27
66
  (wire): PublicConfig => ({
28
67
  runtimeMode: wire.runtime_mode,
29
68
  siteName: wire.site_name,
69
+ signupsEnabled: wire.signups_enabled,
70
+ regions: wire.regions,
30
71
  }),
31
72
  )
package/src/sampleData.ts CHANGED
@@ -3,8 +3,11 @@ import { z } from 'zod'
3
3
  /**
4
4
  * Wire shape for `POST /v1/workspaces/:id/sample-data`.
5
5
  *
6
- * The endpoint takes no body. The response is a count per object type, so a
7
- * caller can tell the reader what the button just did without a second query.
6
+ * The endpoint takes no body. Existing records stay; the fixture is inserted
7
+ * next to them. A second install of the same fixture is `409` when a sample
8
+ * email or domain is already present. The response is a count per object type,
9
+ * so a caller can tell the reader what the button just did without a second
10
+ * query.
8
11
  */
9
12
 
10
13
  export interface SampleDataCounts {
@@ -20,6 +23,8 @@ export interface SampleDataCounts {
20
23
  readonly enquiries: number
21
24
  readonly roles: number
22
25
  readonly candidates: number
26
+ readonly events: number
27
+ readonly attendances: number
23
28
  }
24
29
 
25
30
  export const sampleDataCountsSchema: z.ZodType<SampleDataCounts, unknown> = z
@@ -36,6 +41,8 @@ export const sampleDataCountsSchema: z.ZodType<SampleDataCounts, unknown> = z
36
41
  enquiries: z.number().int().nonnegative(),
37
42
  roles: z.number().int().nonnegative(),
38
43
  candidates: z.number().int().nonnegative(),
44
+ events: z.number().int().nonnegative(),
45
+ attendances: z.number().int().nonnegative(),
39
46
  })
40
47
  .transform(
41
48
  (wire): SampleDataCounts => ({
@@ -51,5 +58,7 @@ export const sampleDataCountsSchema: z.ZodType<SampleDataCounts, unknown> = z
51
58
  enquiries: wire.enquiries,
52
59
  roles: wire.roles,
53
60
  candidates: wire.candidates,
61
+ events: wire.events,
62
+ attendances: wire.attendances,
54
63
  }),
55
64
  )
package/src/session.ts CHANGED
@@ -86,16 +86,92 @@ export const workspaceSchema: z.ZodType<Workspace, unknown> = z
86
86
  }),
87
87
  )
88
88
 
89
+ /**
90
+ * One workspace the signed-in account belongs to, as `GET /v1/auth/workspaces`
91
+ * returns it. `role` is this account's membership, not a workspace setting.
92
+ */
93
+ export interface AccountWorkspace {
94
+ readonly id: string
95
+ readonly name: string
96
+ readonly slug: string
97
+ readonly timezone: string
98
+ readonly role: MemberRole
99
+ }
100
+
101
+ export const accountWorkspaceSchema: z.ZodType<AccountWorkspace, unknown> = z
102
+ .object({
103
+ id: idSchema,
104
+ name: z.string(),
105
+ slug: z.string(),
106
+ timezone: z.string(),
107
+ role: z.enum(MEMBER_ROLES),
108
+ })
109
+ .transform(
110
+ (wire): AccountWorkspace => ({
111
+ id: wire.id,
112
+ name: wire.name,
113
+ slug: wire.slug,
114
+ timezone: wire.timezone,
115
+ role: wire.role,
116
+ }),
117
+ )
118
+
119
+ /** Body for `POST /v1/auth/workspace`: move this session into a membership. */
120
+ export interface SwitchWorkspaceInput {
121
+ readonly workspaceId: string
122
+ }
123
+
124
+ export function switchWorkspaceBody(input: SwitchWorkspaceInput): Record<string, unknown> {
125
+ return { workspace_id: input.workspaceId }
126
+ }
127
+
128
+ export const HANDBOOK_TEMPLATE_IDS = [
129
+ 'startup',
130
+ 'agency',
131
+ 'nonprofit',
132
+ 'community',
133
+ 'professional-services',
134
+ 'creator',
135
+ ] as const
136
+
137
+ export type HandbookTemplateId = (typeof HANDBOOK_TEMPLATE_IDS)[number]
138
+
89
139
  export interface CreateWorkspaceInput {
90
140
  readonly name: string
91
141
  readonly slug: string
92
142
  readonly timezone: string
93
143
  }
94
144
 
145
+ export interface SeedHandbookInput {
146
+ readonly handbookTemplate: HandbookTemplateId
147
+ readonly replace?: boolean | undefined
148
+ }
149
+
150
+ export interface SeedHandbookResult {
151
+ readonly handbookPages: number
152
+ }
153
+
154
+ export const seedHandbookResultSchema: z.ZodType<SeedHandbookResult, unknown> = z
155
+ .object({
156
+ handbook_pages: z.number(),
157
+ })
158
+ .transform(
159
+ (wire): SeedHandbookResult => ({
160
+ handbookPages: wire.handbook_pages,
161
+ }),
162
+ )
163
+
95
164
  export function createWorkspaceBody(input: CreateWorkspaceInput): Record<string, unknown> {
96
165
  return { name: input.name, slug: input.slug, timezone: input.timezone }
97
166
  }
98
167
 
168
+ export function seedHandbookBody(input: SeedHandbookInput): Record<string, unknown> {
169
+ return definedFields({
170
+ handbook_template: input.handbookTemplate,
171
+ replace: input.replace,
172
+ })
173
+ }
174
+
99
175
  /** Settings a workspace admin can change. */
100
176
  export interface UpdateWorkspaceInput {
101
177
  readonly name?: string