@vellumai/credential-executor 0.11.8 → 0.11.9-staging.1

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.
@@ -22,7 +22,10 @@
22
22
  "./redacted-credential": "./src/redacted-credential.ts",
23
23
  "./secret-detection": "./src/secret-detection.ts",
24
24
  "./stripe-currency": "./src/stripe-currency.ts",
25
- "./error": "./src/error.ts"
25
+ "./error": "./src/error.ts",
26
+ "./reactions": "./src/reactions.ts",
27
+ "./guardian-requests": "./src/guardian-requests.ts",
28
+ "./platform-credential": "./src/platform-credential.ts"
26
29
  },
27
30
  "scripts": {
28
31
  "typecheck": "bunx tsc --noEmit",
@@ -0,0 +1,18 @@
1
+ /**
2
+ * Canonical vocabulary for a guardian request's lifecycle status, shared by
3
+ * the gateway that owns the request rows, the daemon that decides and
4
+ * projects them, and the web that renders the projection.
5
+ */
6
+ import { z } from "zod";
7
+
8
+ export const GUARDIAN_REQUEST_STATUS_VALUES = [
9
+ "pending",
10
+ "approved",
11
+ "denied",
12
+ "expired",
13
+ "cancelled",
14
+ ] as const;
15
+ export const GuardianRequestStatusSchema = z.enum(
16
+ GUARDIAN_REQUEST_STATUS_VALUES,
17
+ );
18
+ export type GuardianRequestStatus = z.infer<typeof GuardianRequestStatusSchema>;
@@ -28,6 +28,7 @@ export * from "./rpc.js";
28
28
  export * from "./trust-rules.js";
29
29
  export * from "./ingress.js";
30
30
  export * from "./no-response.js";
31
+ export * from "./platform-credential.js";
31
32
  export * from "./remote-web-pairing.js";
32
33
  export * from "./twilio-ingress.js";
33
34
  export * from "./url-normalization.js";
@@ -0,0 +1,41 @@
1
+ /**
2
+ * Wire contract for asking an assistant whether its stored platform-managed
3
+ * credential still authenticates.
4
+ *
5
+ * The daemon route is the authoritative serving side:
6
+ * - `POST /v1/platform/verify-credential`
7
+ * (`assistant/src/runtime/routes/platform-routes.ts`)
8
+ *
9
+ * The daemon's platform client produces the verdict, the route reports it,
10
+ * and the `vellum` CLI reads it before deciding whether a stored key can be
11
+ * re-injected (`cli/src/lib/assistant-api-key-resolution.ts`), so all three
12
+ * share one definition and cannot silently drift. The web app reads the same
13
+ * shape through its generated daemon client.
14
+ */
15
+ import { z } from "zod";
16
+
17
+ /**
18
+ * What the platform said about the stored credential, right now.
19
+ *
20
+ * - `valid`: the platform accepted it.
21
+ * - `rejected`: the platform refused it (unauthorized or forbidden); the
22
+ * credential needs replacing.
23
+ * - `unknown`: the check itself could not run (no credential stored, the
24
+ * platform unreachable, a server error). Not evidence either way.
25
+ */
26
+ export const PlatformCredentialVerificationStatusSchema = z.enum([
27
+ "valid",
28
+ "rejected",
29
+ "unknown",
30
+ ]);
31
+ export type PlatformCredentialVerificationStatus = z.infer<
32
+ typeof PlatformCredentialVerificationStatusSchema
33
+ >;
34
+
35
+ /** `POST /v1/platform/verify-credential` response body. */
36
+ export const PlatformVerifyCredentialResponseSchema = z.object({
37
+ status: PlatformCredentialVerificationStatusSchema,
38
+ });
39
+ export type PlatformVerifyCredentialResponse = z.infer<
40
+ typeof PlatformVerifyCredentialResponseSchema
41
+ >;
@@ -0,0 +1,60 @@
1
+ /**
2
+ * Canonical vocabulary for a reaction's emoji, shared by every service that
3
+ * handles one: the gateway that normalizes it, the daemon that stores and
4
+ * projects it, and the web that renders it.
5
+ *
6
+ * The kind is said by the channel rather than inferred from how the emoji
7
+ * is spelled. Modelled on Zulip's `reaction_type`, the one surveyed system
8
+ * that separates the namespace from the name.
9
+ *
10
+ * `shortcode` is a name in a channel's own namespace whose kind the channel
11
+ * does not disclose: Slack sends `+1` for the standard emoji and `blob_wave`
12
+ * for a workspace upload with nothing to tell them apart, and only the
13
+ * workspace token can resolve the second. It is a distinct kind from
14
+ * `unicode`, not a stand-in for an unknown one.
15
+ */
16
+ import { z } from "zod";
17
+
18
+ export const REACTION_EMOJI_KINDS = ["unicode", "shortcode", "custom"] as const;
19
+ export type ReactionEmojiKind = (typeof REACTION_EMOJI_KINDS)[number];
20
+
21
+ /**
22
+ * The typed emoji fields every schema that carries a reaction spreads in,
23
+ * so the wire contract, the stored envelopes, and the response projection
24
+ * describe one shape. Optional throughout: a persisted row or a replayed
25
+ * payload may carry only the spelling.
26
+ */
27
+ export const ReactionEmojiFieldsSchema = z.object({
28
+ /** Which namespace the emoji was drawn from. */
29
+ emojiKind: z.enum(REACTION_EMOJI_KINDS).optional(),
30
+ /**
31
+ * The emoji's name in that namespace: the character itself for `unicode`,
32
+ * the bare name for `shortcode` and `custom`. Never a mention form.
33
+ */
34
+ emojiName: z.string().optional(),
35
+ /** The channel's id for a `custom` emoji, absent for every other kind. */
36
+ emojiId: z.string().optional(),
37
+ /** Whether a `custom` emoji animates. Absent for every other kind. */
38
+ emojiAnimated: z.boolean().optional(),
39
+ });
40
+ export type ReactionEmojiFields = z.infer<typeof ReactionEmojiFieldsSchema>;
41
+
42
+ /**
43
+ * The typed emoji fields a source actually carries, with undefined ones
44
+ * omitted: an absent key and a present-but-undefined one serialize alike, but the
45
+ * stored envelope and the response should carry only what was declared. Every writer of a reaction shape (the wire
46
+ * payload, both stored envelopes, the response projection) copies the
47
+ * fields through this rather than restating the four-way pick.
48
+ */
49
+ export function pickReactionEmojiFields(
50
+ source: ReactionEmojiFields,
51
+ ): ReactionEmojiFields {
52
+ return {
53
+ ...(source.emojiKind !== undefined ? { emojiKind: source.emojiKind } : {}),
54
+ ...(source.emojiName !== undefined ? { emojiName: source.emojiName } : {}),
55
+ ...(source.emojiId !== undefined ? { emojiId: source.emojiId } : {}),
56
+ ...(source.emojiAnimated !== undefined
57
+ ? { emojiAnimated: source.emojiAnimated }
58
+ : {}),
59
+ };
60
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@vellumai/credential-executor",
3
- "version": "0.11.8",
3
+ "version": "0.11.9-staging.1",
4
4
  "license": "MIT",
5
5
  "type": "module",
6
6
  "exports": {
@@ -80,6 +80,7 @@ mock.module("pino", () => ({ default: mockPinoLogger }));
80
80
  mock.module("pino-pretty", () => ({ default: (): object => ({}) }));
81
81
 
82
82
  // Import after mocking
83
+ import { initLogger } from "../logger.js";
83
84
  import { runCesMigrations } from "../migrations/runner.js";
84
85
 
85
86
  // ---------------------------------------------------------------------------
@@ -119,6 +120,9 @@ function makeMigration(id: string): CesMigration {
119
120
 
120
121
  describe("runCesMigrations", () => {
121
122
  beforeEach(() => {
123
+ // Rebuild the module-level root logger from the mocked pino, discarding any
124
+ // real logger a previously-executed test file left cached.
125
+ initLogger({ dir: undefined, retentionDays: 0 });
122
126
  mockFileExists = false;
123
127
  mockFileContents = null;
124
128
  existsSyncFn.mockClear();