@withloops.ai/contracts 0.3.0 → 0.3.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.
@@ -16,6 +16,7 @@ export declare const SyncAuth: z.ZodDiscriminatedUnion<[z.ZodObject<{
16
16
  type: z.ZodLiteral<"oauth2">;
17
17
  authorizeUrl: z.ZodURL;
18
18
  tokenUrl: z.ZodURL;
19
+ clientId: z.ZodOptional<z.ZodString>;
19
20
  scopes: z.ZodDefault<z.ZodArray<z.ZodString>>;
20
21
  refresh: z.ZodDefault<z.ZodBoolean>;
21
22
  }, z.core.$strip>, z.ZodObject<{
@@ -127,6 +128,7 @@ export declare const SyncManifest: z.ZodObject<{
127
128
  type: z.ZodLiteral<"oauth2">;
128
129
  authorizeUrl: z.ZodURL;
129
130
  tokenUrl: z.ZodURL;
131
+ clientId: z.ZodOptional<z.ZodString>;
130
132
  scopes: z.ZodDefault<z.ZodArray<z.ZodString>>;
131
133
  refresh: z.ZodDefault<z.ZodBoolean>;
132
134
  }, z.core.$strip>, z.ZodObject<{
@@ -385,6 +387,7 @@ export declare const ManifestV1: z.ZodObject<{
385
387
  type: z.ZodLiteral<"oauth2">;
386
388
  authorizeUrl: z.ZodURL;
387
389
  tokenUrl: z.ZodURL;
390
+ clientId: z.ZodOptional<z.ZodString>;
388
391
  scopes: z.ZodDefault<z.ZodArray<z.ZodString>>;
389
392
  refresh: z.ZodDefault<z.ZodBoolean>;
390
393
  }, z.core.$strip>, z.ZodObject<{
package/dist/manifest.js CHANGED
@@ -28,6 +28,8 @@ export const SyncAuth = z.discriminatedUnion('type', [
28
28
  type: z.literal('oauth2'),
29
29
  authorizeUrl: HttpsUrl,
30
30
  tokenUrl: HttpsUrl,
31
+ /** The developer's OAuth client id at their own service (public). The secret never goes in the manifest: it lives in the vault (APP_CLIENT_SECRET_REF). Added in 0.3.1. */
32
+ clientId: z.string().min(1).max(256).optional(),
31
33
  scopes: z.array(z.string().min(1)).default([]),
32
34
  refresh: z.boolean().default(true),
33
35
  }),
@@ -74,6 +74,7 @@ export declare const AppVersionRecord: z.ZodObject<{
74
74
  type: z.ZodLiteral<"oauth2">;
75
75
  authorizeUrl: z.ZodURL;
76
76
  tokenUrl: z.ZodURL;
77
+ clientId: z.ZodOptional<z.ZodString>;
77
78
  scopes: z.ZodDefault<z.ZodArray<z.ZodString>>;
78
79
  refresh: z.ZodDefault<z.ZodBoolean>;
79
80
  }, z.core.$strip>, z.ZodObject<{
package/dist/trust.d.ts CHANGED
@@ -125,6 +125,29 @@ export declare const SecretRef: z.ZodObject<{
125
125
  name: z.ZodString;
126
126
  }, z.core.$strip>;
127
127
  export type SecretRef = z.infer<typeof SecretRef>;
128
+ /**
129
+ * The developer's OAuth client secret for their own service is stored once per app under this reserved install id,
130
+ * in the app owner's workspace: `{ installId: APP_CLIENT_INSTALL_ID, workspaceId: app.ownerWorkspaceId, appId, name: 'oauth_client_secret' }`.
131
+ * Uninstall never deletes it; only deleting the app does. Added in 0.3.1.
132
+ */
133
+ export declare const APP_CLIENT_INSTALL_ID: "ins_appclient";
134
+ export declare const APP_CLIENT_SECRET_NAME: "oauth_client_secret";
135
+ export declare function appClientSecretRef(appId: string, ownerWorkspaceId: string): SecretRef;
136
+ /** Engine-side code exchange for an app connecting OUT (the handoff at api.thesoogroup.com/oauth/callback). Added in 0.3.1. */
137
+ export declare const OAuthCodeExchange: z.ZodObject<{
138
+ install: z.ZodObject<{
139
+ workspaceId: z.ZodString;
140
+ installId: z.ZodString;
141
+ appId: z.ZodString;
142
+ }, z.core.$strip>;
143
+ ownerWorkspaceId: z.ZodString;
144
+ tokenUrl: z.ZodString;
145
+ clientId: z.ZodString;
146
+ code: z.ZodString;
147
+ codeVerifier: z.ZodOptional<z.ZodString>;
148
+ redirectUri: z.ZodString;
149
+ }, z.core.$strip>;
150
+ export type OAuthCodeExchange = z.infer<typeof OAuthCodeExchange>;
128
151
  /** What anyone outside the engine may see about a secret: never the value. */
129
152
  export declare const SecretInfo: z.ZodObject<{
130
153
  name: z.ZodString;
@@ -172,4 +195,12 @@ export interface EngineVaultRpc {
172
195
  deleteSecrets(installId: string): Promise<{
173
196
  deleted: number;
174
197
  }>;
198
+ /** Reads the app's client secret, POSTs to tokenUrl, stores access/refresh tokens for the install itself. Values never come back. Added in 0.3.1. */
199
+ exchangeOAuthCode(input: OAuthCodeExchange): Promise<{
200
+ ok: true;
201
+ expiresAt: string | null;
202
+ } | {
203
+ ok: false;
204
+ error: string;
205
+ }>;
175
206
  }
package/dist/trust.js CHANGED
@@ -92,6 +92,26 @@ export const SecretRef = z.object({
92
92
  appId: AppId,
93
93
  name: SecretName,
94
94
  });
95
+ /**
96
+ * The developer's OAuth client secret for their own service is stored once per app under this reserved install id,
97
+ * in the app owner's workspace: `{ installId: APP_CLIENT_INSTALL_ID, workspaceId: app.ownerWorkspaceId, appId, name: 'oauth_client_secret' }`.
98
+ * Uninstall never deletes it; only deleting the app does. Added in 0.3.1.
99
+ */
100
+ export const APP_CLIENT_INSTALL_ID = 'ins_appclient';
101
+ export const APP_CLIENT_SECRET_NAME = 'oauth_client_secret';
102
+ export function appClientSecretRef(appId, ownerWorkspaceId) {
103
+ return { installId: APP_CLIENT_INSTALL_ID, workspaceId: ownerWorkspaceId, appId, name: APP_CLIENT_SECRET_NAME };
104
+ }
105
+ /** Engine-side code exchange for an app connecting OUT (the handoff at api.thesoogroup.com/oauth/callback). Added in 0.3.1. */
106
+ export const OAuthCodeExchange = z.object({
107
+ install: SecretRef.omit({ name: true }),
108
+ ownerWorkspaceId: WorkspaceId,
109
+ tokenUrl: z.string().url(),
110
+ clientId: z.string().min(1),
111
+ code: z.string().min(1),
112
+ codeVerifier: z.string().min(43).max(128).optional(),
113
+ redirectUri: z.string().url(),
114
+ });
95
115
  /** What anyone outside the engine may see about a secret: never the value. */
96
116
  export const SecretInfo = z.object({
97
117
  name: SecretName,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@withloops.ai/contracts",
3
- "version": "0.3.0",
3
+ "version": "0.3.1",
4
4
  "description": "The Loops developer platform contracts (zod): app manifest v1, scopes, events, the /v1 API envelope and registry records. Everything else builds on these.",
5
5
  "type": "module",
6
6
  "license": "UNLICENSED",
package/src/manifest.ts CHANGED
@@ -36,6 +36,8 @@ export const SyncAuth = z.discriminatedUnion('type', [
36
36
  type: z.literal('oauth2'),
37
37
  authorizeUrl: HttpsUrl,
38
38
  tokenUrl: HttpsUrl,
39
+ /** The developer's OAuth client id at their own service (public). The secret never goes in the manifest: it lives in the vault (APP_CLIENT_SECRET_REF). Added in 0.3.1. */
40
+ clientId: z.string().min(1).max(256).optional(),
39
41
  scopes: z.array(z.string().min(1)).default([]),
40
42
  refresh: z.boolean().default(true),
41
43
  }),
package/src/trust.ts CHANGED
@@ -122,6 +122,29 @@ export const SecretRef = z.object({
122
122
  });
123
123
  export type SecretRef = z.infer<typeof SecretRef>;
124
124
 
125
+ /**
126
+ * The developer's OAuth client secret for their own service is stored once per app under this reserved install id,
127
+ * in the app owner's workspace: `{ installId: APP_CLIENT_INSTALL_ID, workspaceId: app.ownerWorkspaceId, appId, name: 'oauth_client_secret' }`.
128
+ * Uninstall never deletes it; only deleting the app does. Added in 0.3.1.
129
+ */
130
+ export const APP_CLIENT_INSTALL_ID = 'ins_appclient' as const;
131
+ export const APP_CLIENT_SECRET_NAME = 'oauth_client_secret' as const;
132
+ export function appClientSecretRef(appId: string, ownerWorkspaceId: string): SecretRef {
133
+ return { installId: APP_CLIENT_INSTALL_ID, workspaceId: ownerWorkspaceId, appId, name: APP_CLIENT_SECRET_NAME };
134
+ }
135
+
136
+ /** Engine-side code exchange for an app connecting OUT (the handoff at api.thesoogroup.com/oauth/callback). Added in 0.3.1. */
137
+ export const OAuthCodeExchange = z.object({
138
+ install: SecretRef.omit({ name: true }),
139
+ ownerWorkspaceId: WorkspaceId,
140
+ tokenUrl: z.string().url(),
141
+ clientId: z.string().min(1),
142
+ code: z.string().min(1),
143
+ codeVerifier: z.string().min(43).max(128).optional(),
144
+ redirectUri: z.string().url(),
145
+ });
146
+ export type OAuthCodeExchange = z.infer<typeof OAuthCodeExchange>;
147
+
125
148
  /** What anyone outside the engine may see about a secret: never the value. */
126
149
  export const SecretInfo = z.object({
127
150
  name: SecretName,
@@ -156,4 +179,6 @@ export interface EngineVaultRpc {
156
179
  listSecrets(installId: string): Promise<SecretInfo[]>;
157
180
  /** Uninstall calls this; returns how many rows went. */
158
181
  deleteSecrets(installId: string): Promise<{ deleted: number }>;
182
+ /** Reads the app's client secret, POSTs to tokenUrl, stores access/refresh tokens for the install itself. Values never come back. Added in 0.3.1. */
183
+ exchangeOAuthCode(input: OAuthCodeExchange): Promise<{ ok: true; expiresAt: string | null } | { ok: false; error: string }>;
159
184
  }