@company-semantics/contracts 58.3.0 → 58.5.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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@company-semantics/contracts",
3
- "version": "58.3.0",
3
+ "version": "58.5.0",
4
4
  "private": false,
5
5
  "repository": {
6
6
  "type": "git",
@@ -22,9 +22,12 @@ import type { ISO8601Timestamp } from "./types";
22
22
 
23
23
  /**
24
24
  * Target of an execution action.
25
- * Currently supports Slack integration; extensible for future integrations.
25
+ * Slack carries an optional workspace qualifier; BambooHR is addressed by
26
+ * connectionId alone (the org has at most one HRIS connection), so its
27
+ * target is bare (ADR-BE-610).
26
28
  */
27
- export type ExecutionTarget = { type: "slack"; workspaceId?: string };
29
+ export type ExecutionTarget =
30
+ { type: "slack"; workspaceId?: string } | { type: "bamboohr" };
28
31
 
29
32
  // =============================================================================
30
33
  // Initiator
package/src/index.ts CHANGED
@@ -687,6 +687,7 @@ export type { OrgDirectoryPerson, OrgDirectoryResponse } from "./org/index";
687
687
  // caller's own directory rather than supplied by the caller.
688
688
  export {
689
689
  BATCH_INVITE_PERSONS_MAX,
690
+ INVITE_EXPIRY_DAYS,
690
691
  BATCH_INVITE_SKIP_REASONS,
691
692
  BatchInviteSkipReasonSchema,
692
693
  BatchInviteRequestSchema,
@@ -20,6 +20,10 @@ alongside `Meetings`, `Comms`, and `Docs`.
20
20
  its enum mirrors the backend's `ConnectionRevokedReason` exactly — the app
21
21
  `parse`s this projection, so a value missing from the enum throws rather than
22
22
  degrades (ADR-CONTRACTS-138).
23
+ - `credentialState: 'disconnected'` is a user-chosen stop, not a failure
24
+ (backend ADR-BE-610): imported data and sync history remain, `subdomain` and
25
+ `lastSyncAt` stay populated for the Reconnect flow, `connectionId` and
26
+ `revokedReason` are null, and `syncHealth` is null (nothing is broken).
23
27
  - `HrConnectInputSchema` carries only the customer's provider `subdomain`; no
24
28
  secrets or provider credentials live in contracts.
25
29
  - Pure vocabulary — `zod` is the only runtime import (vocabulary-guard).
@@ -33,26 +33,37 @@ export const HrConnectionStatusSchema = z
33
33
  "whenever the integration cannot sync — read `credentialState` to " +
34
34
  "tell a never-connected integration from one whose grant died.",
35
35
  }),
36
- credentialState: z.enum(["usable", "unusable", "absent"]).meta({
37
- description:
38
- "Why the integration is or is not working. 'usable' — a connection " +
39
- "exists and its credential works (`connected` is true). 'unusable' " +
40
- " a connection exists but its credential cannot be used (expired " +
41
- "or revoked grant); previously synced data remains, and the user " +
42
- "must reconnect. 'absent' no connection at all. Distinguishing " +
43
- "'unusable' from 'absent' is the whole point: both leave " +
44
- "`connected` false, but only one of them is the user's fault to fix " +
45
- "by connecting for the first time.",
46
- }),
36
+ credentialState: z
37
+ .enum(["usable", "unusable", "disconnected", "absent"])
38
+ .meta({
39
+ description:
40
+ "Why the integration is or is not working. 'usable' a connection " +
41
+ "exists and its credential works (`connected` is true). 'unusable' " +
42
+ " a connection exists but its credential cannot be used (expired " +
43
+ "or revoked grant); previously synced data remains, and the user " +
44
+ "must reconnect. 'disconnected' the user chose to stop syncing " +
45
+ "(ADR-BE-610): credentials are gone by intent, imported data and " +
46
+ "sync history remain, and Reconnect resumes the same integration " +
47
+ "identity rather than starting over; nothing is broken, so it " +
48
+ "earns neutral treatment, not the needs-attention treatment " +
49
+ "'unusable' gets. 'absent' — no connection at all. The three " +
50
+ "not-connected states all leave `connected` false but ask " +
51
+ "different things of the reader: 'unusable' is 'fix me', " +
52
+ "'disconnected' is 'resume when ready', 'absent' is 'connect for " +
53
+ "the first time'.",
54
+ }),
47
55
  connectionId: z
48
56
  .string()
49
57
  .nullable()
50
58
  .meta({
51
59
  description:
52
60
  "Stable id of the connection row — the handle the app passes to " +
53
- "`integration.disconnect`. Present whenever a connection exists, " +
54
- "including when `credentialState` is 'unusable', so a dead " +
55
- "integration can still be disconnected. Null only when 'absent'.",
61
+ "`integration.disconnect`. Present whenever there is something to " +
62
+ "disconnect, including when `credentialState` is 'unusable', so a " +
63
+ "dead integration can still be disconnected. Null when 'absent' " +
64
+ "and when 'disconnected' — a disconnected row is retained for " +
65
+ "history/identity (ADR-BE-610) but there is no credential left to " +
66
+ "disconnect, so no disconnect handle is offered.",
56
67
  }),
57
68
  subdomain: z
58
69
  .string()
@@ -106,8 +117,9 @@ export const HrConnectionStatusSchema = z
106
117
  "restored there. The distinction matters because the four cases " +
107
118
  "ask different things of the reader: three are 'click Reconnect' " +
108
119
  "and one is 'go fix it in the provider first'. Null whenever " +
109
- "`credentialState` is not 'unusable', and null on a connection " +
110
- "revoked before this field existed.",
120
+ "`credentialState` is not 'unusable' (including 'disconnected', " +
121
+ "which is chosen, not suffered), and null on a connection revoked " +
122
+ "before this field existed.",
111
123
  }),
112
124
  })
113
125
  .meta({
package/src/org/README.md CHANGED
@@ -163,6 +163,7 @@ Shared type vocabulary for organization ownership, type classification, and tran
163
163
  - `INVITE_BATCH_ITEM_REASONS` — Why an item is not `sent`.
164
164
  - `INVITE_BATCH_ITEM_STATUSES` — Per-recipient outcome within a batch. - `eligible` — will be invited when the batch is sent. - `excluded` —…
165
165
  - `INVITE_BATCH_STATUSES` — Batch lifecycle. - `draft` — created, membership not yet evaluated.
166
+ - `INVITE_EXPIRY_DAYS` — How many days an invitation link stays redeemable.
166
167
  - `IdentityTrustLevel` _(type)_ — Identity Trust Level — org's identity posture
167
168
  - `IntegrationRequest` _(type)_ — Advisory integration request created by a member.
168
169
  - `IntegrationRequestStatus` _(type)_ — Status of an integration request from a member.
package/src/org/index.ts CHANGED
@@ -412,6 +412,7 @@ export {
412
412
  OrgDirectoryPersonSchema,
413
413
  OrgDirectoryResponseSchema,
414
414
  BATCH_INVITE_PERSONS_MAX,
415
+ INVITE_EXPIRY_DAYS,
415
416
  BATCH_INVITE_SKIP_REASONS,
416
417
  BatchInviteSkipReasonSchema,
417
418
  BatchInviteRequestSchema,
@@ -854,6 +854,20 @@ export type OrgDirectoryResponse = z.infer<typeof OrgDirectoryResponseSchema>;
854
854
  */
855
855
  export const BATCH_INVITE_PERSONS_MAX = 100;
856
856
 
857
+ /**
858
+ * How many days an invitation link stays redeemable.
859
+ *
860
+ * Shared vocabulary, not prose: the backend stamps `expires_at` from this when
861
+ * it mints an invite, and the review surface states the same window to the
862
+ * person about to send one. It lived in both places as a literal and drifted —
863
+ * the copy still promised seven days after the policy moved.
864
+ *
865
+ * A SECURITY parameter as much as a UX one: it bounds how long a leaked invite
866
+ * link stays usable, so widening it is a deliberate trust-model change rather
867
+ * than a copy edit.
868
+ */
869
+ export const INVITE_EXPIRY_DAYS = 30;
870
+
857
871
  /** @deprecated Use {@link CreateInviteBatchRequestSchema}. Removed in 58.0.0. */
858
872
  export const BatchInviteRequestSchema = z.object({
859
873
  personIds: z.array(z.string().uuid()).min(1).max(BATCH_INVITE_PERSONS_MAX),