@zapier/policy-context 0.3.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/dist/index.cjs +326 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.cts +149 -0
- package/dist/index.d.ts +149 -0
- package/dist/index.js +285 -0
- package/dist/index.js.map +1 -0
- package/package.json +53 -0
package/dist/index.cjs
ADDED
|
@@ -0,0 +1,326 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __defProp = Object.defineProperty;
|
|
3
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
4
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
5
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
6
|
+
var __export = (target, all) => {
|
|
7
|
+
for (var name in all)
|
|
8
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
9
|
+
};
|
|
10
|
+
var __copyProps = (to, from, except, desc) => {
|
|
11
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
12
|
+
for (let key of __getOwnPropNames(from))
|
|
13
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
14
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
15
|
+
}
|
|
16
|
+
return to;
|
|
17
|
+
};
|
|
18
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
19
|
+
|
|
20
|
+
// src/index.ts
|
|
21
|
+
var index_exports = {};
|
|
22
|
+
__export(index_exports, {
|
|
23
|
+
ActionRunContextSchema: () => ActionRunContextSchema,
|
|
24
|
+
BuildActionRunContextOptionsSchema: () => BuildActionRunContextOptionsSchema,
|
|
25
|
+
BuildHttpRequestContextOptionsSchema: () => BuildHttpRequestContextOptionsSchema,
|
|
26
|
+
HttpRequestContextSchema: () => HttpRequestContextSchema,
|
|
27
|
+
IGNORED_HEADERS: () => IGNORED_HEADERS,
|
|
28
|
+
JsonValueSchema: () => JsonValueSchema,
|
|
29
|
+
RequestContextSchema: () => RequestContextSchema,
|
|
30
|
+
buildActionResource: () => buildActionResource,
|
|
31
|
+
buildActionRunContext: () => buildActionRunContext,
|
|
32
|
+
buildBroadActionResource: () => buildBroadActionResource,
|
|
33
|
+
buildDomainHttpConditions: () => buildDomainHttpConditions,
|
|
34
|
+
buildExactActionConditions: () => buildExactActionConditions,
|
|
35
|
+
buildExactHttpConditions: () => buildExactHttpConditions,
|
|
36
|
+
buildHttpRequestContext: () => buildHttpRequestContext,
|
|
37
|
+
toExactPolicy: () => toExactPolicy
|
|
38
|
+
});
|
|
39
|
+
module.exports = __toCommonJS(index_exports);
|
|
40
|
+
|
|
41
|
+
// src/types.ts
|
|
42
|
+
var import_zod = require("zod");
|
|
43
|
+
var JsonValueSchema = import_zod.z.custom();
|
|
44
|
+
var HttpRequestContextSchema = import_zod.z.object({
|
|
45
|
+
request_type: import_zod.z.literal("http_request"),
|
|
46
|
+
method: import_zod.z.string(),
|
|
47
|
+
/** Full URL including query string, e.g. "https://api.example.com/v1/foo?bar=baz" */
|
|
48
|
+
url: import_zod.z.string(),
|
|
49
|
+
/** Filtered headers (IGNORED_HEADERS excluded, keys lowercased) */
|
|
50
|
+
headers: import_zod.z.record(import_zod.z.string(), import_zod.z.string()).optional(),
|
|
51
|
+
/** Raw body string */
|
|
52
|
+
body: import_zod.z.string().optional(),
|
|
53
|
+
/** Parsed JSON body */
|
|
54
|
+
body_json: JsonValueSchema.optional(),
|
|
55
|
+
/** Zapier connection ID used for this request */
|
|
56
|
+
connection_id: import_zod.z.string().optional(),
|
|
57
|
+
/** Optional human-readable reason for the request */
|
|
58
|
+
reason: import_zod.z.string().optional()
|
|
59
|
+
});
|
|
60
|
+
var ActionRunContextSchema = import_zod.z.object({
|
|
61
|
+
request_type: import_zod.z.literal("action_run"),
|
|
62
|
+
selected_api: import_zod.z.string(),
|
|
63
|
+
action_type: import_zod.z.string(),
|
|
64
|
+
action_key: import_zod.z.string(),
|
|
65
|
+
connection_id: import_zod.z.string().optional(),
|
|
66
|
+
inputs: JsonValueSchema.optional(),
|
|
67
|
+
reason: import_zod.z.string().optional()
|
|
68
|
+
});
|
|
69
|
+
var RequestContextSchema = import_zod.z.discriminatedUnion("request_type", [
|
|
70
|
+
HttpRequestContextSchema,
|
|
71
|
+
ActionRunContextSchema
|
|
72
|
+
]);
|
|
73
|
+
|
|
74
|
+
// src/constants.ts
|
|
75
|
+
var IGNORED_HEADERS = /* @__PURE__ */ new Set([
|
|
76
|
+
// Auth / credentials — never include in contexts or policy conditions
|
|
77
|
+
"authorization",
|
|
78
|
+
"x-relay-authorization",
|
|
79
|
+
"x-relay-authentication-id",
|
|
80
|
+
"x-api-key",
|
|
81
|
+
"cookie",
|
|
82
|
+
"set-cookie",
|
|
83
|
+
"proxy-authorization",
|
|
84
|
+
// HTTP infrastructure — varies per-request, not policy-relevant
|
|
85
|
+
"host",
|
|
86
|
+
"connection",
|
|
87
|
+
"content-length",
|
|
88
|
+
"transfer-encoding",
|
|
89
|
+
"accept-encoding",
|
|
90
|
+
"user-agent",
|
|
91
|
+
"accept",
|
|
92
|
+
"accept-language",
|
|
93
|
+
"sec-fetch-mode",
|
|
94
|
+
// Proxy / forwarding — infrastructure, not meaningful for policy
|
|
95
|
+
"x-forwarded-for",
|
|
96
|
+
"x-forwarded-host",
|
|
97
|
+
"x-forwarded-proto",
|
|
98
|
+
"x-real-ip",
|
|
99
|
+
// Proxy internal — sdkapi-specific headers
|
|
100
|
+
"x-is-interactive-session",
|
|
101
|
+
"x-relay-callback-url"
|
|
102
|
+
]);
|
|
103
|
+
|
|
104
|
+
// src/builders.ts
|
|
105
|
+
var import_zod2 = require("zod");
|
|
106
|
+
var BuildHttpRequestContextOptionsSchema = import_zod2.z.object({
|
|
107
|
+
method: import_zod2.z.string(),
|
|
108
|
+
/** Raw URL string. Will be normalized with https:// if no protocol present. */
|
|
109
|
+
url: import_zod2.z.string(),
|
|
110
|
+
/** Raw headers from the request. Will be filtered through IGNORED_HEADERS. */
|
|
111
|
+
headers: import_zod2.z.record(
|
|
112
|
+
import_zod2.z.string(),
|
|
113
|
+
import_zod2.z.union([import_zod2.z.string(), import_zod2.z.array(import_zod2.z.string()), import_zod2.z.undefined()])
|
|
114
|
+
).optional(),
|
|
115
|
+
/** Raw body string */
|
|
116
|
+
body: import_zod2.z.string().nullable().optional(),
|
|
117
|
+
/** Pre-parsed JSON body (e.g. from Fastify's automatic JSON parsing) */
|
|
118
|
+
body_json: JsonValueSchema.optional(),
|
|
119
|
+
/** Connection ID associated with this request */
|
|
120
|
+
connection_id: import_zod2.z.string().optional()
|
|
121
|
+
});
|
|
122
|
+
function buildHttpRequestContext(options) {
|
|
123
|
+
const url = options.url.includes("://") ? options.url : `https://${options.url}`;
|
|
124
|
+
const headers = {};
|
|
125
|
+
if (options.headers) {
|
|
126
|
+
for (const [key, value] of Object.entries(options.headers)) {
|
|
127
|
+
const lowerKey = key.toLowerCase();
|
|
128
|
+
if (!IGNORED_HEADERS.has(lowerKey) && typeof value === "string") {
|
|
129
|
+
headers[lowerKey] = value;
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
return HttpRequestContextSchema.parse({
|
|
134
|
+
request_type: "http_request",
|
|
135
|
+
method: options.method,
|
|
136
|
+
url,
|
|
137
|
+
headers,
|
|
138
|
+
body: typeof options.body === "string" ? options.body : void 0,
|
|
139
|
+
body_json: typeof options.body_json === "object" && options.body_json !== null ? options.body_json : void 0,
|
|
140
|
+
connection_id: options.connection_id
|
|
141
|
+
});
|
|
142
|
+
}
|
|
143
|
+
var BuildActionRunContextOptionsSchema = import_zod2.z.object({
|
|
144
|
+
selected_api: import_zod2.z.string(),
|
|
145
|
+
action_type: import_zod2.z.string(),
|
|
146
|
+
action_key: import_zod2.z.string(),
|
|
147
|
+
connection_id: import_zod2.z.string().optional(),
|
|
148
|
+
inputs: JsonValueSchema.optional()
|
|
149
|
+
});
|
|
150
|
+
function buildActionRunContext(options) {
|
|
151
|
+
return ActionRunContextSchema.parse({
|
|
152
|
+
request_type: "action_run",
|
|
153
|
+
selected_api: options.selected_api,
|
|
154
|
+
action_type: options.action_type,
|
|
155
|
+
action_key: options.action_key,
|
|
156
|
+
connection_id: options.connection_id,
|
|
157
|
+
inputs: options.inputs
|
|
158
|
+
});
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
// src/conditions.ts
|
|
162
|
+
function buildExactHttpConditions(context) {
|
|
163
|
+
const conditions = [
|
|
164
|
+
{ path: ["method"], operator: "equals", value: context.method }
|
|
165
|
+
];
|
|
166
|
+
let parsedUrl;
|
|
167
|
+
try {
|
|
168
|
+
parsedUrl = new URL(context.url);
|
|
169
|
+
} catch {
|
|
170
|
+
console.debug(
|
|
171
|
+
"buildExactHttpConditions: unparseable URL, using raw value",
|
|
172
|
+
{ url: context.url }
|
|
173
|
+
);
|
|
174
|
+
conditions.push({
|
|
175
|
+
path: ["url"],
|
|
176
|
+
operator: "matches_url",
|
|
177
|
+
value: context.url
|
|
178
|
+
});
|
|
179
|
+
return conditions;
|
|
180
|
+
}
|
|
181
|
+
const urlWithoutQuery = `${parsedUrl.protocol}//${parsedUrl.host}${parsedUrl.pathname}`;
|
|
182
|
+
conditions.push({
|
|
183
|
+
path: ["url"],
|
|
184
|
+
operator: "matches_url",
|
|
185
|
+
value: urlWithoutQuery
|
|
186
|
+
});
|
|
187
|
+
const seenKeys = /* @__PURE__ */ new Set();
|
|
188
|
+
for (const key of parsedUrl.searchParams.keys()) {
|
|
189
|
+
if (seenKeys.has(key)) continue;
|
|
190
|
+
seenKeys.add(key);
|
|
191
|
+
const values = parsedUrl.searchParams.getAll(key);
|
|
192
|
+
conditions.push({
|
|
193
|
+
path: ["url", "query", key],
|
|
194
|
+
operator: "equals",
|
|
195
|
+
value: values
|
|
196
|
+
});
|
|
197
|
+
}
|
|
198
|
+
if (context.body_json !== void 0 && context.body_json !== null) {
|
|
199
|
+
conditions.push({
|
|
200
|
+
path: ["body_json"],
|
|
201
|
+
operator: "equals",
|
|
202
|
+
value: context.body_json
|
|
203
|
+
});
|
|
204
|
+
}
|
|
205
|
+
if (context.headers) {
|
|
206
|
+
for (const [key, value] of Object.entries(context.headers)) {
|
|
207
|
+
if (!IGNORED_HEADERS.has(key.toLowerCase()) && typeof value === "string") {
|
|
208
|
+
conditions.push({
|
|
209
|
+
path: ["headers", key.toLowerCase()],
|
|
210
|
+
operator: "equals",
|
|
211
|
+
value
|
|
212
|
+
});
|
|
213
|
+
}
|
|
214
|
+
}
|
|
215
|
+
}
|
|
216
|
+
return conditions;
|
|
217
|
+
}
|
|
218
|
+
function buildDomainHttpConditions(context) {
|
|
219
|
+
let host;
|
|
220
|
+
try {
|
|
221
|
+
host = new URL(context.url).host;
|
|
222
|
+
} catch {
|
|
223
|
+
return null;
|
|
224
|
+
}
|
|
225
|
+
return [
|
|
226
|
+
{
|
|
227
|
+
path: ["url", "host"],
|
|
228
|
+
operator: "matches_host",
|
|
229
|
+
value: host
|
|
230
|
+
}
|
|
231
|
+
];
|
|
232
|
+
}
|
|
233
|
+
function buildExactActionConditions(context) {
|
|
234
|
+
const conditions = [];
|
|
235
|
+
if (context.inputs !== void 0 && context.inputs !== null && typeof context.inputs === "object") {
|
|
236
|
+
conditions.push({
|
|
237
|
+
path: ["params"],
|
|
238
|
+
operator: "equals",
|
|
239
|
+
value: context.inputs
|
|
240
|
+
});
|
|
241
|
+
}
|
|
242
|
+
return conditions;
|
|
243
|
+
}
|
|
244
|
+
function buildActionResource(context) {
|
|
245
|
+
return `action/${context.selected_api}/${context.action_type}/${context.action_key}`;
|
|
246
|
+
}
|
|
247
|
+
function buildBroadActionResource(context) {
|
|
248
|
+
return `action/${context.selected_api}/*/*`;
|
|
249
|
+
}
|
|
250
|
+
|
|
251
|
+
// src/policies.ts
|
|
252
|
+
function buildAuthStatement(authenticationId) {
|
|
253
|
+
return {
|
|
254
|
+
effect: "allow",
|
|
255
|
+
permissions: ["can_use"],
|
|
256
|
+
resources: [`authentication/${authenticationId}`],
|
|
257
|
+
conditions: []
|
|
258
|
+
};
|
|
259
|
+
}
|
|
260
|
+
function httpContextToPolicy(context) {
|
|
261
|
+
const statements = [];
|
|
262
|
+
if (context.connection_id) {
|
|
263
|
+
statements.push(buildAuthStatement(context.connection_id));
|
|
264
|
+
}
|
|
265
|
+
const conditions = buildExactHttpConditions(context);
|
|
266
|
+
try {
|
|
267
|
+
const queryKeys = [...new URL(context.url).searchParams.keys()];
|
|
268
|
+
const uniqueKeys = [...new Set(queryKeys)];
|
|
269
|
+
conditions.push({
|
|
270
|
+
path: ["url", "query"],
|
|
271
|
+
operator: "keys_in",
|
|
272
|
+
value: uniqueKeys
|
|
273
|
+
});
|
|
274
|
+
} catch {
|
|
275
|
+
conditions.push({
|
|
276
|
+
path: ["url", "query"],
|
|
277
|
+
operator: "keys_in",
|
|
278
|
+
value: []
|
|
279
|
+
});
|
|
280
|
+
}
|
|
281
|
+
statements.push({
|
|
282
|
+
effect: "allow",
|
|
283
|
+
permissions: ["can_execute"],
|
|
284
|
+
resources: ["relay/http"],
|
|
285
|
+
conditions
|
|
286
|
+
});
|
|
287
|
+
return { version: 2, statements };
|
|
288
|
+
}
|
|
289
|
+
function actionContextToPolicy(context) {
|
|
290
|
+
const statements = [];
|
|
291
|
+
if (context.connection_id) {
|
|
292
|
+
statements.push(buildAuthStatement(context.connection_id));
|
|
293
|
+
}
|
|
294
|
+
statements.push({
|
|
295
|
+
effect: "allow",
|
|
296
|
+
permissions: ["can_execute"],
|
|
297
|
+
resources: [buildActionResource(context)],
|
|
298
|
+
conditions: buildExactActionConditions(context)
|
|
299
|
+
});
|
|
300
|
+
return { version: 2, statements };
|
|
301
|
+
}
|
|
302
|
+
function toExactPolicy(context) {
|
|
303
|
+
if (context.request_type === "http_request") {
|
|
304
|
+
return httpContextToPolicy(context);
|
|
305
|
+
}
|
|
306
|
+
return actionContextToPolicy(context);
|
|
307
|
+
}
|
|
308
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
309
|
+
0 && (module.exports = {
|
|
310
|
+
ActionRunContextSchema,
|
|
311
|
+
BuildActionRunContextOptionsSchema,
|
|
312
|
+
BuildHttpRequestContextOptionsSchema,
|
|
313
|
+
HttpRequestContextSchema,
|
|
314
|
+
IGNORED_HEADERS,
|
|
315
|
+
JsonValueSchema,
|
|
316
|
+
RequestContextSchema,
|
|
317
|
+
buildActionResource,
|
|
318
|
+
buildActionRunContext,
|
|
319
|
+
buildBroadActionResource,
|
|
320
|
+
buildDomainHttpConditions,
|
|
321
|
+
buildExactActionConditions,
|
|
322
|
+
buildExactHttpConditions,
|
|
323
|
+
buildHttpRequestContext,
|
|
324
|
+
toExactPolicy
|
|
325
|
+
});
|
|
326
|
+
//# sourceMappingURL=index.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/index.ts","../src/types.ts","../src/constants.ts","../src/builders.ts","../src/conditions.ts","../src/policies.ts"],"sourcesContent":["// ABOUTME: Public API for @zapier/policy-context.\n// ABOUTME: Shared context types, builders, and condition generators for sdkapi + approvalsapi.\n\nexport {\n HttpRequestContextSchema,\n ActionRunContextSchema,\n RequestContextSchema,\n JsonValueSchema,\n type HttpRequestContext,\n type ActionRunContext,\n type RequestContext,\n} from \"./types.ts\";\n\nexport { IGNORED_HEADERS } from \"./constants.ts\";\n\nexport {\n buildHttpRequestContext,\n buildActionRunContext,\n BuildHttpRequestContextOptionsSchema,\n BuildActionRunContextOptionsSchema,\n type BuildHttpRequestContextOptions,\n type BuildActionRunContextOptions,\n} from \"./builders.ts\";\n\nexport {\n buildExactHttpConditions,\n buildDomainHttpConditions,\n buildExactActionConditions,\n buildActionResource,\n buildBroadActionResource,\n} from \"./conditions.ts\";\n\nexport { toExactPolicy } from \"./policies.ts\";\n","// ABOUTME: Canonical request context types shared between sdkapi and approvalsapi.\n// ABOUTME: These define the contract for how requests are described in approval flows and policy evaluation.\n\nimport { z } from \"zod\";\nimport type { JsonValue } from \"@zapier/policy-schema\";\n\n/**\n * Zod schema for arbitrary JSON values. Used across context schemas for\n * unstructured fields like `body_json` and `inputs`.\n */\nexport const JsonValueSchema = z.custom<JsonValue>();\n\n/**\n * HTTP request context for approval/policy flows.\n * Sent by sdkapi when a relay request is denied, stored by approvalsapi,\n * and used to build policy conditions.\n */\nexport const HttpRequestContextSchema = z.object({\n request_type: z.literal(\"http_request\"),\n method: z.string(),\n /** Full URL including query string, e.g. \"https://api.example.com/v1/foo?bar=baz\" */\n url: z.string(),\n /** Filtered headers (IGNORED_HEADERS excluded, keys lowercased) */\n headers: z.record(z.string(), z.string()).optional(),\n /** Raw body string */\n body: z.string().optional(),\n /** Parsed JSON body */\n body_json: JsonValueSchema.optional(),\n /** Zapier connection ID used for this request */\n connection_id: z.string().optional(),\n /** Optional human-readable reason for the request */\n reason: z.string().optional(),\n});\nexport type HttpRequestContext = z.infer<typeof HttpRequestContextSchema>;\n\n/**\n * Action run context for approval/policy flows.\n * Sent by sdkapi when an action run is denied, stored by approvalsapi,\n * and used to build policy conditions.\n */\nexport const ActionRunContextSchema = z.object({\n request_type: z.literal(\"action_run\"),\n selected_api: z.string(),\n action_type: z.string(),\n action_key: z.string(),\n connection_id: z.string().optional(),\n inputs: JsonValueSchema.optional(),\n reason: z.string().optional(),\n});\nexport type ActionRunContext = z.infer<typeof ActionRunContextSchema>;\n\n/**\n * Discriminated union of all request context types.\n */\nexport const RequestContextSchema = z.discriminatedUnion(\"request_type\", [\n HttpRequestContextSchema,\n ActionRunContextSchema,\n]);\nexport type RequestContext = z.infer<typeof RequestContextSchema>;\n","// ABOUTME: Canonical set of headers to exclude when building request contexts.\n// ABOUTME: Shared between sdkapi (context creation) and approvalsapi (condition building).\n\n/**\n * Headers to exclude when building request contexts from raw HTTP requests.\n *\n * These are either sensitive (auth credentials), HTTP infrastructure headers\n * that vary per-request, or proxy-internal headers that are not meaningful\n * for policy decisions.\n */\nexport const IGNORED_HEADERS = new Set([\n // Auth / credentials — never include in contexts or policy conditions\n \"authorization\",\n \"x-relay-authorization\",\n \"x-relay-authentication-id\",\n \"x-api-key\",\n \"cookie\",\n \"set-cookie\",\n \"proxy-authorization\",\n\n // HTTP infrastructure — varies per-request, not policy-relevant\n \"host\",\n \"connection\",\n \"content-length\",\n \"transfer-encoding\",\n \"accept-encoding\",\n \"user-agent\",\n \"accept\",\n \"accept-language\",\n \"sec-fetch-mode\",\n\n // Proxy / forwarding — infrastructure, not meaningful for policy\n \"x-forwarded-for\",\n \"x-forwarded-host\",\n \"x-forwarded-proto\",\n \"x-real-ip\",\n\n // Proxy internal — sdkapi-specific headers\n \"x-is-interactive-session\",\n \"x-relay-callback-url\",\n]);\n","// ABOUTME: Canonical builders for creating request contexts from raw request parts.\n// ABOUTME: Used by sdkapi to build both approval contexts and policy eval contexts.\n\nimport { z } from \"zod\";\nimport {\n HttpRequestContextSchema,\n ActionRunContextSchema,\n JsonValueSchema,\n type HttpRequestContext,\n type ActionRunContext,\n} from \"./types.ts\";\nimport { IGNORED_HEADERS } from \"./constants.ts\";\n\nexport const BuildHttpRequestContextOptionsSchema = z.object({\n method: z.string(),\n /** Raw URL string. Will be normalized with https:// if no protocol present. */\n url: z.string(),\n /** Raw headers from the request. Will be filtered through IGNORED_HEADERS. */\n headers: z\n .record(\n z.string(),\n z.union([z.string(), z.array(z.string()), z.undefined()]),\n )\n .optional(),\n /** Raw body string */\n body: z.string().nullable().optional(),\n /** Pre-parsed JSON body (e.g. from Fastify's automatic JSON parsing) */\n body_json: JsonValueSchema.optional(),\n /** Connection ID associated with this request */\n connection_id: z.string().optional(),\n});\nexport type BuildHttpRequestContextOptions = z.infer<\n typeof BuildHttpRequestContextOptionsSchema\n>;\n\n/**\n * Build a canonical HttpRequestContext from raw request parts.\n *\n * This is the single source of truth for how HTTP request contexts are created.\n * Both sdkapi (for approval creation) and approvalsapi (for context storage)\n * should use this to ensure the context shape is consistent.\n *\n * - Normalizes URL (adds https:// if missing)\n * - Filters headers through IGNORED_HEADERS\n * - Only includes string-valued headers (drops string[] values like set-cookie)\n */\nexport function buildHttpRequestContext(\n options: BuildHttpRequestContextOptions,\n): HttpRequestContext {\n // Normalize URL — SDK CLI strips the protocol\n const url = options.url.includes(\"://\")\n ? options.url\n : `https://${options.url}`;\n\n // Filter headers: exclude ignored, lowercase keys, string values only\n const headers: Record<string, string> = {};\n if (options.headers) {\n for (const [key, value] of Object.entries(options.headers)) {\n const lowerKey = key.toLowerCase();\n if (!IGNORED_HEADERS.has(lowerKey) && typeof value === \"string\") {\n headers[lowerKey] = value;\n }\n }\n }\n\n return HttpRequestContextSchema.parse({\n request_type: \"http_request\",\n method: options.method,\n url,\n headers,\n body: typeof options.body === \"string\" ? options.body : undefined,\n body_json:\n typeof options.body_json === \"object\" && options.body_json !== null\n ? options.body_json\n : undefined,\n connection_id: options.connection_id,\n });\n}\n\nexport const BuildActionRunContextOptionsSchema = z.object({\n selected_api: z.string(),\n action_type: z.string(),\n action_key: z.string(),\n connection_id: z.string().optional(),\n inputs: JsonValueSchema.optional(),\n});\nexport type BuildActionRunContextOptions = z.infer<\n typeof BuildActionRunContextOptionsSchema\n>;\n\n/**\n * Build a canonical ActionRunContext from raw action parts.\n */\nexport function buildActionRunContext(\n options: BuildActionRunContextOptions,\n): ActionRunContext {\n return ActionRunContextSchema.parse({\n request_type: \"action_run\",\n selected_api: options.selected_api,\n action_type: options.action_type,\n action_key: options.action_key,\n connection_id: options.connection_id,\n inputs: options.inputs,\n });\n}\n","// ABOUTME: Builds policy conditions from stored request contexts.\n// ABOUTME: Used by approvalsapi's \"allow exact request\" and \"allow domain\" instant policy flows.\n\nimport type { Condition } from \"@zapier/policy-schema\";\nimport type { HttpRequestContext, ActionRunContext } from \"./types.ts\";\nimport { IGNORED_HEADERS } from \"./constants.ts\";\n\n/**\n * Build conditions that match an exact HTTP request.\n *\n * Handles the matches_url / query param split correctly:\n * - `matches_url` only supports scheme+host+port+path (no query string per spec)\n * - Query parameters are added as separate decomposed conditions on `url.query.<key>`\n *\n * @returns Condition[] for a relay/http permission statement\n */\nexport function buildExactHttpConditions(\n context: HttpRequestContext,\n): Condition[] {\n const conditions: Condition[] = [\n { path: [\"method\"], operator: \"equals\", value: context.method },\n ];\n\n // Parse the URL to separate path from query params\n let parsedUrl: URL;\n try {\n parsedUrl = new URL(context.url);\n } catch {\n // URL is unparseable — use it as-is (will fail matches_url, but that's correct)\n console.debug(\n \"buildExactHttpConditions: unparseable URL, using raw value\",\n { url: context.url },\n );\n conditions.push({\n path: [\"url\"],\n operator: \"matches_url\",\n value: context.url,\n });\n return conditions;\n }\n\n // matches_url condition uses URL without query string (per @zapier/policy spec)\n const urlWithoutQuery = `${parsedUrl.protocol}//${parsedUrl.host}${parsedUrl.pathname}`;\n conditions.push({\n path: [\"url\"],\n operator: \"matches_url\",\n value: urlWithoutQuery,\n });\n\n // Add decomposed conditions for each query parameter.\n // Use getAll to properly handle multi-value params (e.g. ?tag=a&tag=b → [\"a\", \"b\"]).\n const seenKeys = new Set<string>();\n for (const key of parsedUrl.searchParams.keys()) {\n if (seenKeys.has(key)) continue;\n seenKeys.add(key);\n const values = parsedUrl.searchParams.getAll(key);\n conditions.push({\n path: [\"url\", \"query\", key],\n operator: \"equals\",\n value: values,\n });\n }\n\n // body_json condition\n if (context.body_json !== undefined && context.body_json !== null) {\n conditions.push({\n path: [\"body_json\"],\n operator: \"equals\",\n value: context.body_json,\n });\n }\n\n // Header conditions (filtered through IGNORED_HEADERS again for safety)\n if (context.headers) {\n for (const [key, value] of Object.entries(context.headers)) {\n if (\n !IGNORED_HEADERS.has(key.toLowerCase()) &&\n typeof value === \"string\"\n ) {\n conditions.push({\n path: [\"headers\", key.toLowerCase()],\n operator: \"equals\",\n value,\n });\n }\n }\n }\n\n return conditions;\n}\n\n/**\n * Build conditions that match any request to a given domain.\n * Extracts the host from the context URL.\n *\n * @returns Condition[] for a relay/http permission statement, or null if URL is unparseable\n */\nexport function buildDomainHttpConditions(\n context: HttpRequestContext,\n): Condition[] | null {\n let host: string;\n try {\n host = new URL(context.url).host;\n } catch {\n return null;\n }\n\n return [\n {\n path: [\"url\", \"host\"],\n operator: \"matches_host\",\n value: host,\n },\n ];\n}\n\n/**\n * Build conditions that match an exact action run (with inputs).\n *\n * @returns Condition[] for an action permission statement\n */\nexport function buildExactActionConditions(\n context: ActionRunContext,\n): Condition[] {\n const conditions: Condition[] = [];\n\n if (\n context.inputs !== undefined &&\n context.inputs !== null &&\n typeof context.inputs === \"object\"\n ) {\n conditions.push({\n path: [\"params\"],\n operator: \"equals\",\n value: context.inputs,\n });\n }\n\n return conditions;\n}\n\n/**\n * Build the resource string for an action.\n * Format: action/{selected_api}/{action_type}/{action_key}\n */\nexport function buildActionResource(context: ActionRunContext): string {\n return `action/${context.selected_api}/${context.action_type}/${context.action_key}`;\n}\n\n/**\n * Build a broad action resource that matches all actions for an app.\n * Format: action/{selected_api}/{wildcard}/{wildcard}\n */\nexport function buildBroadActionResource(context: ActionRunContext): string {\n return `action/${context.selected_api}/*/*`;\n}\n","// ABOUTME: Assembles complete Policy objects from request contexts.\n// ABOUTME: Single source of truth for \"exact request\" instant policies used by web UI and API.\n\nimport type { Policy, Statement } from \"@zapier/policy-schema\";\nimport type {\n RequestContext,\n HttpRequestContext,\n ActionRunContext,\n} from \"./types.ts\";\nimport {\n buildExactHttpConditions,\n buildExactActionConditions,\n buildActionResource,\n} from \"./conditions.ts\";\n\n/**\n * Build a `can_use` authentication statement, if the context has a connection_id.\n */\nfunction buildAuthStatement(authenticationId: string): Statement {\n return {\n effect: \"allow\",\n permissions: [\"can_use\"],\n resources: [`authentication/${authenticationId}`],\n conditions: [],\n };\n}\n\n/**\n * Build an exact-match policy from an HTTP request context.\n *\n * Produces a policy that allows only the specific request described by the context:\n * - `can_use` statement for the authentication (if present)\n * - `can_execute` statement for `relay/http` with conditions from `buildExactHttpConditions`\n * plus a `keys_in` guard restricting allowed query parameter keys\n */\nfunction httpContextToPolicy(context: HttpRequestContext): Policy {\n const statements: Statement[] = [];\n\n if (context.connection_id) {\n statements.push(buildAuthStatement(context.connection_id));\n }\n\n const conditions = buildExactHttpConditions(context);\n\n // Add a keys_in guard so only the query param keys present in the original\n // request are allowed — blocks injection of extra query params.\n try {\n const queryKeys = [...new URL(context.url).searchParams.keys()];\n const uniqueKeys = [...new Set(queryKeys)];\n conditions.push({\n path: [\"url\", \"query\"],\n operator: \"keys_in\",\n value: uniqueKeys,\n });\n } catch {\n // If URL parsing fails, block all query params\n conditions.push({\n path: [\"url\", \"query\"],\n operator: \"keys_in\",\n value: [],\n });\n }\n\n statements.push({\n effect: \"allow\",\n permissions: [\"can_execute\"],\n resources: [\"relay/http\"],\n conditions,\n });\n\n return { version: 2, statements };\n}\n\n/**\n * Build an exact-match policy from an action run context.\n *\n * Produces a policy that allows only the specific action described by the context:\n * - `can_use` statement for the authentication (if present)\n * - `can_execute` statement for the action resource with input conditions\n */\nfunction actionContextToPolicy(context: ActionRunContext): Policy {\n const statements: Statement[] = [];\n\n if (context.connection_id) {\n statements.push(buildAuthStatement(context.connection_id));\n }\n\n statements.push({\n effect: \"allow\",\n permissions: [\"can_execute\"],\n resources: [buildActionResource(context)],\n conditions: buildExactActionConditions(context),\n });\n\n return { version: 2, statements };\n}\n\n/**\n * Build an exact-match policy from any supported request context.\n *\n * This is the single source of truth for \"allow this exact request\" instant policies.\n * Used by the web UI and anywhere else that needs to produce an exact policy from a context.\n */\nexport function toExactPolicy(context: RequestContext): Policy {\n if (context.request_type === \"http_request\") {\n return httpContextToPolicy(context);\n }\n return actionContextToPolicy(context);\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;;ACGA,iBAAkB;AAOX,IAAM,kBAAkB,aAAE,OAAkB;AAO5C,IAAM,2BAA2B,aAAE,OAAO;AAAA,EAC/C,cAAc,aAAE,QAAQ,cAAc;AAAA,EACtC,QAAQ,aAAE,OAAO;AAAA;AAAA,EAEjB,KAAK,aAAE,OAAO;AAAA;AAAA,EAEd,SAAS,aAAE,OAAO,aAAE,OAAO,GAAG,aAAE,OAAO,CAAC,EAAE,SAAS;AAAA;AAAA,EAEnD,MAAM,aAAE,OAAO,EAAE,SAAS;AAAA;AAAA,EAE1B,WAAW,gBAAgB,SAAS;AAAA;AAAA,EAEpC,eAAe,aAAE,OAAO,EAAE,SAAS;AAAA;AAAA,EAEnC,QAAQ,aAAE,OAAO,EAAE,SAAS;AAC9B,CAAC;AAQM,IAAM,yBAAyB,aAAE,OAAO;AAAA,EAC7C,cAAc,aAAE,QAAQ,YAAY;AAAA,EACpC,cAAc,aAAE,OAAO;AAAA,EACvB,aAAa,aAAE,OAAO;AAAA,EACtB,YAAY,aAAE,OAAO;AAAA,EACrB,eAAe,aAAE,OAAO,EAAE,SAAS;AAAA,EACnC,QAAQ,gBAAgB,SAAS;AAAA,EACjC,QAAQ,aAAE,OAAO,EAAE,SAAS;AAC9B,CAAC;AAMM,IAAM,uBAAuB,aAAE,mBAAmB,gBAAgB;AAAA,EACvE;AAAA,EACA;AACF,CAAC;;;AC/CM,IAAM,kBAAkB,oBAAI,IAAI;AAAA;AAAA,EAErC;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA;AAAA,EAGA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA;AAAA,EAGA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA;AAAA,EAGA;AAAA,EACA;AACF,CAAC;;;ACrCD,IAAAA,cAAkB;AAUX,IAAM,uCAAuC,cAAE,OAAO;AAAA,EAC3D,QAAQ,cAAE,OAAO;AAAA;AAAA,EAEjB,KAAK,cAAE,OAAO;AAAA;AAAA,EAEd,SAAS,cACN;AAAA,IACC,cAAE,OAAO;AAAA,IACT,cAAE,MAAM,CAAC,cAAE,OAAO,GAAG,cAAE,MAAM,cAAE,OAAO,CAAC,GAAG,cAAE,UAAU,CAAC,CAAC;AAAA,EAC1D,EACC,SAAS;AAAA;AAAA,EAEZ,MAAM,cAAE,OAAO,EAAE,SAAS,EAAE,SAAS;AAAA;AAAA,EAErC,WAAW,gBAAgB,SAAS;AAAA;AAAA,EAEpC,eAAe,cAAE,OAAO,EAAE,SAAS;AACrC,CAAC;AAgBM,SAAS,wBACd,SACoB;AAEpB,QAAM,MAAM,QAAQ,IAAI,SAAS,KAAK,IAClC,QAAQ,MACR,WAAW,QAAQ,GAAG;AAG1B,QAAM,UAAkC,CAAC;AACzC,MAAI,QAAQ,SAAS;AACnB,eAAW,CAAC,KAAK,KAAK,KAAK,OAAO,QAAQ,QAAQ,OAAO,GAAG;AAC1D,YAAM,WAAW,IAAI,YAAY;AACjC,UAAI,CAAC,gBAAgB,IAAI,QAAQ,KAAK,OAAO,UAAU,UAAU;AAC/D,gBAAQ,QAAQ,IAAI;AAAA,MACtB;AAAA,IACF;AAAA,EACF;AAEA,SAAO,yBAAyB,MAAM;AAAA,IACpC,cAAc;AAAA,IACd,QAAQ,QAAQ;AAAA,IAChB;AAAA,IACA;AAAA,IACA,MAAM,OAAO,QAAQ,SAAS,WAAW,QAAQ,OAAO;AAAA,IACxD,WACE,OAAO,QAAQ,cAAc,YAAY,QAAQ,cAAc,OAC3D,QAAQ,YACR;AAAA,IACN,eAAe,QAAQ;AAAA,EACzB,CAAC;AACH;AAEO,IAAM,qCAAqC,cAAE,OAAO;AAAA,EACzD,cAAc,cAAE,OAAO;AAAA,EACvB,aAAa,cAAE,OAAO;AAAA,EACtB,YAAY,cAAE,OAAO;AAAA,EACrB,eAAe,cAAE,OAAO,EAAE,SAAS;AAAA,EACnC,QAAQ,gBAAgB,SAAS;AACnC,CAAC;AAQM,SAAS,sBACd,SACkB;AAClB,SAAO,uBAAuB,MAAM;AAAA,IAClC,cAAc;AAAA,IACd,cAAc,QAAQ;AAAA,IACtB,aAAa,QAAQ;AAAA,IACrB,YAAY,QAAQ;AAAA,IACpB,eAAe,QAAQ;AAAA,IACvB,QAAQ,QAAQ;AAAA,EAClB,CAAC;AACH;;;ACxFO,SAAS,yBACd,SACa;AACb,QAAM,aAA0B;AAAA,IAC9B,EAAE,MAAM,CAAC,QAAQ,GAAG,UAAU,UAAU,OAAO,QAAQ,OAAO;AAAA,EAChE;AAGA,MAAI;AACJ,MAAI;AACF,gBAAY,IAAI,IAAI,QAAQ,GAAG;AAAA,EACjC,QAAQ;AAEN,YAAQ;AAAA,MACN;AAAA,MACA,EAAE,KAAK,QAAQ,IAAI;AAAA,IACrB;AACA,eAAW,KAAK;AAAA,MACd,MAAM,CAAC,KAAK;AAAA,MACZ,UAAU;AAAA,MACV,OAAO,QAAQ;AAAA,IACjB,CAAC;AACD,WAAO;AAAA,EACT;AAGA,QAAM,kBAAkB,GAAG,UAAU,QAAQ,KAAK,UAAU,IAAI,GAAG,UAAU,QAAQ;AACrF,aAAW,KAAK;AAAA,IACd,MAAM,CAAC,KAAK;AAAA,IACZ,UAAU;AAAA,IACV,OAAO;AAAA,EACT,CAAC;AAID,QAAM,WAAW,oBAAI,IAAY;AACjC,aAAW,OAAO,UAAU,aAAa,KAAK,GAAG;AAC/C,QAAI,SAAS,IAAI,GAAG,EAAG;AACvB,aAAS,IAAI,GAAG;AAChB,UAAM,SAAS,UAAU,aAAa,OAAO,GAAG;AAChD,eAAW,KAAK;AAAA,MACd,MAAM,CAAC,OAAO,SAAS,GAAG;AAAA,MAC1B,UAAU;AAAA,MACV,OAAO;AAAA,IACT,CAAC;AAAA,EACH;AAGA,MAAI,QAAQ,cAAc,UAAa,QAAQ,cAAc,MAAM;AACjE,eAAW,KAAK;AAAA,MACd,MAAM,CAAC,WAAW;AAAA,MAClB,UAAU;AAAA,MACV,OAAO,QAAQ;AAAA,IACjB,CAAC;AAAA,EACH;AAGA,MAAI,QAAQ,SAAS;AACnB,eAAW,CAAC,KAAK,KAAK,KAAK,OAAO,QAAQ,QAAQ,OAAO,GAAG;AAC1D,UACE,CAAC,gBAAgB,IAAI,IAAI,YAAY,CAAC,KACtC,OAAO,UAAU,UACjB;AACA,mBAAW,KAAK;AAAA,UACd,MAAM,CAAC,WAAW,IAAI,YAAY,CAAC;AAAA,UACnC,UAAU;AAAA,UACV;AAAA,QACF,CAAC;AAAA,MACH;AAAA,IACF;AAAA,EACF;AAEA,SAAO;AACT;AAQO,SAAS,0BACd,SACoB;AACpB,MAAI;AACJ,MAAI;AACF,WAAO,IAAI,IAAI,QAAQ,GAAG,EAAE;AAAA,EAC9B,QAAQ;AACN,WAAO;AAAA,EACT;AAEA,SAAO;AAAA,IACL;AAAA,MACE,MAAM,CAAC,OAAO,MAAM;AAAA,MACpB,UAAU;AAAA,MACV,OAAO;AAAA,IACT;AAAA,EACF;AACF;AAOO,SAAS,2BACd,SACa;AACb,QAAM,aAA0B,CAAC;AAEjC,MACE,QAAQ,WAAW,UACnB,QAAQ,WAAW,QACnB,OAAO,QAAQ,WAAW,UAC1B;AACA,eAAW,KAAK;AAAA,MACd,MAAM,CAAC,QAAQ;AAAA,MACf,UAAU;AAAA,MACV,OAAO,QAAQ;AAAA,IACjB,CAAC;AAAA,EACH;AAEA,SAAO;AACT;AAMO,SAAS,oBAAoB,SAAmC;AACrE,SAAO,UAAU,QAAQ,YAAY,IAAI,QAAQ,WAAW,IAAI,QAAQ,UAAU;AACpF;AAMO,SAAS,yBAAyB,SAAmC;AAC1E,SAAO,UAAU,QAAQ,YAAY;AACvC;;;ACzIA,SAAS,mBAAmB,kBAAqC;AAC/D,SAAO;AAAA,IACL,QAAQ;AAAA,IACR,aAAa,CAAC,SAAS;AAAA,IACvB,WAAW,CAAC,kBAAkB,gBAAgB,EAAE;AAAA,IAChD,YAAY,CAAC;AAAA,EACf;AACF;AAUA,SAAS,oBAAoB,SAAqC;AAChE,QAAM,aAA0B,CAAC;AAEjC,MAAI,QAAQ,eAAe;AACzB,eAAW,KAAK,mBAAmB,QAAQ,aAAa,CAAC;AAAA,EAC3D;AAEA,QAAM,aAAa,yBAAyB,OAAO;AAInD,MAAI;AACF,UAAM,YAAY,CAAC,GAAG,IAAI,IAAI,QAAQ,GAAG,EAAE,aAAa,KAAK,CAAC;AAC9D,UAAM,aAAa,CAAC,GAAG,IAAI,IAAI,SAAS,CAAC;AACzC,eAAW,KAAK;AAAA,MACd,MAAM,CAAC,OAAO,OAAO;AAAA,MACrB,UAAU;AAAA,MACV,OAAO;AAAA,IACT,CAAC;AAAA,EACH,QAAQ;AAEN,eAAW,KAAK;AAAA,MACd,MAAM,CAAC,OAAO,OAAO;AAAA,MACrB,UAAU;AAAA,MACV,OAAO,CAAC;AAAA,IACV,CAAC;AAAA,EACH;AAEA,aAAW,KAAK;AAAA,IACd,QAAQ;AAAA,IACR,aAAa,CAAC,aAAa;AAAA,IAC3B,WAAW,CAAC,YAAY;AAAA,IACxB;AAAA,EACF,CAAC;AAED,SAAO,EAAE,SAAS,GAAG,WAAW;AAClC;AASA,SAAS,sBAAsB,SAAmC;AAChE,QAAM,aAA0B,CAAC;AAEjC,MAAI,QAAQ,eAAe;AACzB,eAAW,KAAK,mBAAmB,QAAQ,aAAa,CAAC;AAAA,EAC3D;AAEA,aAAW,KAAK;AAAA,IACd,QAAQ;AAAA,IACR,aAAa,CAAC,aAAa;AAAA,IAC3B,WAAW,CAAC,oBAAoB,OAAO,CAAC;AAAA,IACxC,YAAY,2BAA2B,OAAO;AAAA,EAChD,CAAC;AAED,SAAO,EAAE,SAAS,GAAG,WAAW;AAClC;AAQO,SAAS,cAAc,SAAiC;AAC7D,MAAI,QAAQ,iBAAiB,gBAAgB;AAC3C,WAAO,oBAAoB,OAAO;AAAA,EACpC;AACA,SAAO,sBAAsB,OAAO;AACtC;","names":["import_zod"]}
|
package/dist/index.d.cts
ADDED
|
@@ -0,0 +1,149 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
import * as _zapier_policy_schema from '@zapier/policy-schema';
|
|
3
|
+
import { JsonValue, Condition, Policy } from '@zapier/policy-schema';
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Zod schema for arbitrary JSON values. Used across context schemas for
|
|
7
|
+
* unstructured fields like `body_json` and `inputs`.
|
|
8
|
+
*/
|
|
9
|
+
declare const JsonValueSchema: z.ZodCustom<JsonValue, JsonValue>;
|
|
10
|
+
/**
|
|
11
|
+
* HTTP request context for approval/policy flows.
|
|
12
|
+
* Sent by sdkapi when a relay request is denied, stored by approvalsapi,
|
|
13
|
+
* and used to build policy conditions.
|
|
14
|
+
*/
|
|
15
|
+
declare const HttpRequestContextSchema: z.ZodObject<{
|
|
16
|
+
request_type: z.ZodLiteral<"http_request">;
|
|
17
|
+
method: z.ZodString;
|
|
18
|
+
url: z.ZodString;
|
|
19
|
+
headers: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodString>>;
|
|
20
|
+
body: z.ZodOptional<z.ZodString>;
|
|
21
|
+
body_json: z.ZodOptional<z.ZodCustom<JsonValue, JsonValue>>;
|
|
22
|
+
connection_id: z.ZodOptional<z.ZodString>;
|
|
23
|
+
reason: z.ZodOptional<z.ZodString>;
|
|
24
|
+
}, z.core.$strip>;
|
|
25
|
+
type HttpRequestContext = z.infer<typeof HttpRequestContextSchema>;
|
|
26
|
+
/**
|
|
27
|
+
* Action run context for approval/policy flows.
|
|
28
|
+
* Sent by sdkapi when an action run is denied, stored by approvalsapi,
|
|
29
|
+
* and used to build policy conditions.
|
|
30
|
+
*/
|
|
31
|
+
declare const ActionRunContextSchema: z.ZodObject<{
|
|
32
|
+
request_type: z.ZodLiteral<"action_run">;
|
|
33
|
+
selected_api: z.ZodString;
|
|
34
|
+
action_type: z.ZodString;
|
|
35
|
+
action_key: z.ZodString;
|
|
36
|
+
connection_id: z.ZodOptional<z.ZodString>;
|
|
37
|
+
inputs: z.ZodOptional<z.ZodCustom<JsonValue, JsonValue>>;
|
|
38
|
+
reason: z.ZodOptional<z.ZodString>;
|
|
39
|
+
}, z.core.$strip>;
|
|
40
|
+
type ActionRunContext = z.infer<typeof ActionRunContextSchema>;
|
|
41
|
+
/**
|
|
42
|
+
* Discriminated union of all request context types.
|
|
43
|
+
*/
|
|
44
|
+
declare const RequestContextSchema: z.ZodDiscriminatedUnion<[z.ZodObject<{
|
|
45
|
+
request_type: z.ZodLiteral<"http_request">;
|
|
46
|
+
method: z.ZodString;
|
|
47
|
+
url: z.ZodString;
|
|
48
|
+
headers: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodString>>;
|
|
49
|
+
body: z.ZodOptional<z.ZodString>;
|
|
50
|
+
body_json: z.ZodOptional<z.ZodCustom<JsonValue, JsonValue>>;
|
|
51
|
+
connection_id: z.ZodOptional<z.ZodString>;
|
|
52
|
+
reason: z.ZodOptional<z.ZodString>;
|
|
53
|
+
}, z.core.$strip>, z.ZodObject<{
|
|
54
|
+
request_type: z.ZodLiteral<"action_run">;
|
|
55
|
+
selected_api: z.ZodString;
|
|
56
|
+
action_type: z.ZodString;
|
|
57
|
+
action_key: z.ZodString;
|
|
58
|
+
connection_id: z.ZodOptional<z.ZodString>;
|
|
59
|
+
inputs: z.ZodOptional<z.ZodCustom<JsonValue, JsonValue>>;
|
|
60
|
+
reason: z.ZodOptional<z.ZodString>;
|
|
61
|
+
}, z.core.$strip>], "request_type">;
|
|
62
|
+
type RequestContext = z.infer<typeof RequestContextSchema>;
|
|
63
|
+
|
|
64
|
+
/**
|
|
65
|
+
* Headers to exclude when building request contexts from raw HTTP requests.
|
|
66
|
+
*
|
|
67
|
+
* These are either sensitive (auth credentials), HTTP infrastructure headers
|
|
68
|
+
* that vary per-request, or proxy-internal headers that are not meaningful
|
|
69
|
+
* for policy decisions.
|
|
70
|
+
*/
|
|
71
|
+
declare const IGNORED_HEADERS: Set<string>;
|
|
72
|
+
|
|
73
|
+
declare const BuildHttpRequestContextOptionsSchema: z.ZodObject<{
|
|
74
|
+
method: z.ZodString;
|
|
75
|
+
url: z.ZodString;
|
|
76
|
+
headers: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnion<readonly [z.ZodString, z.ZodArray<z.ZodString>, z.ZodUndefined]>>>;
|
|
77
|
+
body: z.ZodOptional<z.ZodNullable<z.ZodString>>;
|
|
78
|
+
body_json: z.ZodOptional<z.ZodCustom<_zapier_policy_schema.JsonValue, _zapier_policy_schema.JsonValue>>;
|
|
79
|
+
connection_id: z.ZodOptional<z.ZodString>;
|
|
80
|
+
}, z.core.$strip>;
|
|
81
|
+
type BuildHttpRequestContextOptions = z.infer<typeof BuildHttpRequestContextOptionsSchema>;
|
|
82
|
+
/**
|
|
83
|
+
* Build a canonical HttpRequestContext from raw request parts.
|
|
84
|
+
*
|
|
85
|
+
* This is the single source of truth for how HTTP request contexts are created.
|
|
86
|
+
* Both sdkapi (for approval creation) and approvalsapi (for context storage)
|
|
87
|
+
* should use this to ensure the context shape is consistent.
|
|
88
|
+
*
|
|
89
|
+
* - Normalizes URL (adds https:// if missing)
|
|
90
|
+
* - Filters headers through IGNORED_HEADERS
|
|
91
|
+
* - Only includes string-valued headers (drops string[] values like set-cookie)
|
|
92
|
+
*/
|
|
93
|
+
declare function buildHttpRequestContext(options: BuildHttpRequestContextOptions): HttpRequestContext;
|
|
94
|
+
declare const BuildActionRunContextOptionsSchema: z.ZodObject<{
|
|
95
|
+
selected_api: z.ZodString;
|
|
96
|
+
action_type: z.ZodString;
|
|
97
|
+
action_key: z.ZodString;
|
|
98
|
+
connection_id: z.ZodOptional<z.ZodString>;
|
|
99
|
+
inputs: z.ZodOptional<z.ZodCustom<_zapier_policy_schema.JsonValue, _zapier_policy_schema.JsonValue>>;
|
|
100
|
+
}, z.core.$strip>;
|
|
101
|
+
type BuildActionRunContextOptions = z.infer<typeof BuildActionRunContextOptionsSchema>;
|
|
102
|
+
/**
|
|
103
|
+
* Build a canonical ActionRunContext from raw action parts.
|
|
104
|
+
*/
|
|
105
|
+
declare function buildActionRunContext(options: BuildActionRunContextOptions): ActionRunContext;
|
|
106
|
+
|
|
107
|
+
/**
|
|
108
|
+
* Build conditions that match an exact HTTP request.
|
|
109
|
+
*
|
|
110
|
+
* Handles the matches_url / query param split correctly:
|
|
111
|
+
* - `matches_url` only supports scheme+host+port+path (no query string per spec)
|
|
112
|
+
* - Query parameters are added as separate decomposed conditions on `url.query.<key>`
|
|
113
|
+
*
|
|
114
|
+
* @returns Condition[] for a relay/http permission statement
|
|
115
|
+
*/
|
|
116
|
+
declare function buildExactHttpConditions(context: HttpRequestContext): Condition[];
|
|
117
|
+
/**
|
|
118
|
+
* Build conditions that match any request to a given domain.
|
|
119
|
+
* Extracts the host from the context URL.
|
|
120
|
+
*
|
|
121
|
+
* @returns Condition[] for a relay/http permission statement, or null if URL is unparseable
|
|
122
|
+
*/
|
|
123
|
+
declare function buildDomainHttpConditions(context: HttpRequestContext): Condition[] | null;
|
|
124
|
+
/**
|
|
125
|
+
* Build conditions that match an exact action run (with inputs).
|
|
126
|
+
*
|
|
127
|
+
* @returns Condition[] for an action permission statement
|
|
128
|
+
*/
|
|
129
|
+
declare function buildExactActionConditions(context: ActionRunContext): Condition[];
|
|
130
|
+
/**
|
|
131
|
+
* Build the resource string for an action.
|
|
132
|
+
* Format: action/{selected_api}/{action_type}/{action_key}
|
|
133
|
+
*/
|
|
134
|
+
declare function buildActionResource(context: ActionRunContext): string;
|
|
135
|
+
/**
|
|
136
|
+
* Build a broad action resource that matches all actions for an app.
|
|
137
|
+
* Format: action/{selected_api}/{wildcard}/{wildcard}
|
|
138
|
+
*/
|
|
139
|
+
declare function buildBroadActionResource(context: ActionRunContext): string;
|
|
140
|
+
|
|
141
|
+
/**
|
|
142
|
+
* Build an exact-match policy from any supported request context.
|
|
143
|
+
*
|
|
144
|
+
* This is the single source of truth for "allow this exact request" instant policies.
|
|
145
|
+
* Used by the web UI and anywhere else that needs to produce an exact policy from a context.
|
|
146
|
+
*/
|
|
147
|
+
declare function toExactPolicy(context: RequestContext): Policy;
|
|
148
|
+
|
|
149
|
+
export { type ActionRunContext, ActionRunContextSchema, type BuildActionRunContextOptions, BuildActionRunContextOptionsSchema, type BuildHttpRequestContextOptions, BuildHttpRequestContextOptionsSchema, type HttpRequestContext, HttpRequestContextSchema, IGNORED_HEADERS, JsonValueSchema, type RequestContext, RequestContextSchema, buildActionResource, buildActionRunContext, buildBroadActionResource, buildDomainHttpConditions, buildExactActionConditions, buildExactHttpConditions, buildHttpRequestContext, toExactPolicy };
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,149 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
import * as _zapier_policy_schema from '@zapier/policy-schema';
|
|
3
|
+
import { JsonValue, Condition, Policy } from '@zapier/policy-schema';
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Zod schema for arbitrary JSON values. Used across context schemas for
|
|
7
|
+
* unstructured fields like `body_json` and `inputs`.
|
|
8
|
+
*/
|
|
9
|
+
declare const JsonValueSchema: z.ZodCustom<JsonValue, JsonValue>;
|
|
10
|
+
/**
|
|
11
|
+
* HTTP request context for approval/policy flows.
|
|
12
|
+
* Sent by sdkapi when a relay request is denied, stored by approvalsapi,
|
|
13
|
+
* and used to build policy conditions.
|
|
14
|
+
*/
|
|
15
|
+
declare const HttpRequestContextSchema: z.ZodObject<{
|
|
16
|
+
request_type: z.ZodLiteral<"http_request">;
|
|
17
|
+
method: z.ZodString;
|
|
18
|
+
url: z.ZodString;
|
|
19
|
+
headers: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodString>>;
|
|
20
|
+
body: z.ZodOptional<z.ZodString>;
|
|
21
|
+
body_json: z.ZodOptional<z.ZodCustom<JsonValue, JsonValue>>;
|
|
22
|
+
connection_id: z.ZodOptional<z.ZodString>;
|
|
23
|
+
reason: z.ZodOptional<z.ZodString>;
|
|
24
|
+
}, z.core.$strip>;
|
|
25
|
+
type HttpRequestContext = z.infer<typeof HttpRequestContextSchema>;
|
|
26
|
+
/**
|
|
27
|
+
* Action run context for approval/policy flows.
|
|
28
|
+
* Sent by sdkapi when an action run is denied, stored by approvalsapi,
|
|
29
|
+
* and used to build policy conditions.
|
|
30
|
+
*/
|
|
31
|
+
declare const ActionRunContextSchema: z.ZodObject<{
|
|
32
|
+
request_type: z.ZodLiteral<"action_run">;
|
|
33
|
+
selected_api: z.ZodString;
|
|
34
|
+
action_type: z.ZodString;
|
|
35
|
+
action_key: z.ZodString;
|
|
36
|
+
connection_id: z.ZodOptional<z.ZodString>;
|
|
37
|
+
inputs: z.ZodOptional<z.ZodCustom<JsonValue, JsonValue>>;
|
|
38
|
+
reason: z.ZodOptional<z.ZodString>;
|
|
39
|
+
}, z.core.$strip>;
|
|
40
|
+
type ActionRunContext = z.infer<typeof ActionRunContextSchema>;
|
|
41
|
+
/**
|
|
42
|
+
* Discriminated union of all request context types.
|
|
43
|
+
*/
|
|
44
|
+
declare const RequestContextSchema: z.ZodDiscriminatedUnion<[z.ZodObject<{
|
|
45
|
+
request_type: z.ZodLiteral<"http_request">;
|
|
46
|
+
method: z.ZodString;
|
|
47
|
+
url: z.ZodString;
|
|
48
|
+
headers: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodString>>;
|
|
49
|
+
body: z.ZodOptional<z.ZodString>;
|
|
50
|
+
body_json: z.ZodOptional<z.ZodCustom<JsonValue, JsonValue>>;
|
|
51
|
+
connection_id: z.ZodOptional<z.ZodString>;
|
|
52
|
+
reason: z.ZodOptional<z.ZodString>;
|
|
53
|
+
}, z.core.$strip>, z.ZodObject<{
|
|
54
|
+
request_type: z.ZodLiteral<"action_run">;
|
|
55
|
+
selected_api: z.ZodString;
|
|
56
|
+
action_type: z.ZodString;
|
|
57
|
+
action_key: z.ZodString;
|
|
58
|
+
connection_id: z.ZodOptional<z.ZodString>;
|
|
59
|
+
inputs: z.ZodOptional<z.ZodCustom<JsonValue, JsonValue>>;
|
|
60
|
+
reason: z.ZodOptional<z.ZodString>;
|
|
61
|
+
}, z.core.$strip>], "request_type">;
|
|
62
|
+
type RequestContext = z.infer<typeof RequestContextSchema>;
|
|
63
|
+
|
|
64
|
+
/**
|
|
65
|
+
* Headers to exclude when building request contexts from raw HTTP requests.
|
|
66
|
+
*
|
|
67
|
+
* These are either sensitive (auth credentials), HTTP infrastructure headers
|
|
68
|
+
* that vary per-request, or proxy-internal headers that are not meaningful
|
|
69
|
+
* for policy decisions.
|
|
70
|
+
*/
|
|
71
|
+
declare const IGNORED_HEADERS: Set<string>;
|
|
72
|
+
|
|
73
|
+
declare const BuildHttpRequestContextOptionsSchema: z.ZodObject<{
|
|
74
|
+
method: z.ZodString;
|
|
75
|
+
url: z.ZodString;
|
|
76
|
+
headers: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnion<readonly [z.ZodString, z.ZodArray<z.ZodString>, z.ZodUndefined]>>>;
|
|
77
|
+
body: z.ZodOptional<z.ZodNullable<z.ZodString>>;
|
|
78
|
+
body_json: z.ZodOptional<z.ZodCustom<_zapier_policy_schema.JsonValue, _zapier_policy_schema.JsonValue>>;
|
|
79
|
+
connection_id: z.ZodOptional<z.ZodString>;
|
|
80
|
+
}, z.core.$strip>;
|
|
81
|
+
type BuildHttpRequestContextOptions = z.infer<typeof BuildHttpRequestContextOptionsSchema>;
|
|
82
|
+
/**
|
|
83
|
+
* Build a canonical HttpRequestContext from raw request parts.
|
|
84
|
+
*
|
|
85
|
+
* This is the single source of truth for how HTTP request contexts are created.
|
|
86
|
+
* Both sdkapi (for approval creation) and approvalsapi (for context storage)
|
|
87
|
+
* should use this to ensure the context shape is consistent.
|
|
88
|
+
*
|
|
89
|
+
* - Normalizes URL (adds https:// if missing)
|
|
90
|
+
* - Filters headers through IGNORED_HEADERS
|
|
91
|
+
* - Only includes string-valued headers (drops string[] values like set-cookie)
|
|
92
|
+
*/
|
|
93
|
+
declare function buildHttpRequestContext(options: BuildHttpRequestContextOptions): HttpRequestContext;
|
|
94
|
+
declare const BuildActionRunContextOptionsSchema: z.ZodObject<{
|
|
95
|
+
selected_api: z.ZodString;
|
|
96
|
+
action_type: z.ZodString;
|
|
97
|
+
action_key: z.ZodString;
|
|
98
|
+
connection_id: z.ZodOptional<z.ZodString>;
|
|
99
|
+
inputs: z.ZodOptional<z.ZodCustom<_zapier_policy_schema.JsonValue, _zapier_policy_schema.JsonValue>>;
|
|
100
|
+
}, z.core.$strip>;
|
|
101
|
+
type BuildActionRunContextOptions = z.infer<typeof BuildActionRunContextOptionsSchema>;
|
|
102
|
+
/**
|
|
103
|
+
* Build a canonical ActionRunContext from raw action parts.
|
|
104
|
+
*/
|
|
105
|
+
declare function buildActionRunContext(options: BuildActionRunContextOptions): ActionRunContext;
|
|
106
|
+
|
|
107
|
+
/**
|
|
108
|
+
* Build conditions that match an exact HTTP request.
|
|
109
|
+
*
|
|
110
|
+
* Handles the matches_url / query param split correctly:
|
|
111
|
+
* - `matches_url` only supports scheme+host+port+path (no query string per spec)
|
|
112
|
+
* - Query parameters are added as separate decomposed conditions on `url.query.<key>`
|
|
113
|
+
*
|
|
114
|
+
* @returns Condition[] for a relay/http permission statement
|
|
115
|
+
*/
|
|
116
|
+
declare function buildExactHttpConditions(context: HttpRequestContext): Condition[];
|
|
117
|
+
/**
|
|
118
|
+
* Build conditions that match any request to a given domain.
|
|
119
|
+
* Extracts the host from the context URL.
|
|
120
|
+
*
|
|
121
|
+
* @returns Condition[] for a relay/http permission statement, or null if URL is unparseable
|
|
122
|
+
*/
|
|
123
|
+
declare function buildDomainHttpConditions(context: HttpRequestContext): Condition[] | null;
|
|
124
|
+
/**
|
|
125
|
+
* Build conditions that match an exact action run (with inputs).
|
|
126
|
+
*
|
|
127
|
+
* @returns Condition[] for an action permission statement
|
|
128
|
+
*/
|
|
129
|
+
declare function buildExactActionConditions(context: ActionRunContext): Condition[];
|
|
130
|
+
/**
|
|
131
|
+
* Build the resource string for an action.
|
|
132
|
+
* Format: action/{selected_api}/{action_type}/{action_key}
|
|
133
|
+
*/
|
|
134
|
+
declare function buildActionResource(context: ActionRunContext): string;
|
|
135
|
+
/**
|
|
136
|
+
* Build a broad action resource that matches all actions for an app.
|
|
137
|
+
* Format: action/{selected_api}/{wildcard}/{wildcard}
|
|
138
|
+
*/
|
|
139
|
+
declare function buildBroadActionResource(context: ActionRunContext): string;
|
|
140
|
+
|
|
141
|
+
/**
|
|
142
|
+
* Build an exact-match policy from any supported request context.
|
|
143
|
+
*
|
|
144
|
+
* This is the single source of truth for "allow this exact request" instant policies.
|
|
145
|
+
* Used by the web UI and anywhere else that needs to produce an exact policy from a context.
|
|
146
|
+
*/
|
|
147
|
+
declare function toExactPolicy(context: RequestContext): Policy;
|
|
148
|
+
|
|
149
|
+
export { type ActionRunContext, ActionRunContextSchema, type BuildActionRunContextOptions, BuildActionRunContextOptionsSchema, type BuildHttpRequestContextOptions, BuildHttpRequestContextOptionsSchema, type HttpRequestContext, HttpRequestContextSchema, IGNORED_HEADERS, JsonValueSchema, type RequestContext, RequestContextSchema, buildActionResource, buildActionRunContext, buildBroadActionResource, buildDomainHttpConditions, buildExactActionConditions, buildExactHttpConditions, buildHttpRequestContext, toExactPolicy };
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,285 @@
|
|
|
1
|
+
// src/types.ts
|
|
2
|
+
import { z } from "zod";
|
|
3
|
+
var JsonValueSchema = z.custom();
|
|
4
|
+
var HttpRequestContextSchema = z.object({
|
|
5
|
+
request_type: z.literal("http_request"),
|
|
6
|
+
method: z.string(),
|
|
7
|
+
/** Full URL including query string, e.g. "https://api.example.com/v1/foo?bar=baz" */
|
|
8
|
+
url: z.string(),
|
|
9
|
+
/** Filtered headers (IGNORED_HEADERS excluded, keys lowercased) */
|
|
10
|
+
headers: z.record(z.string(), z.string()).optional(),
|
|
11
|
+
/** Raw body string */
|
|
12
|
+
body: z.string().optional(),
|
|
13
|
+
/** Parsed JSON body */
|
|
14
|
+
body_json: JsonValueSchema.optional(),
|
|
15
|
+
/** Zapier connection ID used for this request */
|
|
16
|
+
connection_id: z.string().optional(),
|
|
17
|
+
/** Optional human-readable reason for the request */
|
|
18
|
+
reason: z.string().optional()
|
|
19
|
+
});
|
|
20
|
+
var ActionRunContextSchema = z.object({
|
|
21
|
+
request_type: z.literal("action_run"),
|
|
22
|
+
selected_api: z.string(),
|
|
23
|
+
action_type: z.string(),
|
|
24
|
+
action_key: z.string(),
|
|
25
|
+
connection_id: z.string().optional(),
|
|
26
|
+
inputs: JsonValueSchema.optional(),
|
|
27
|
+
reason: z.string().optional()
|
|
28
|
+
});
|
|
29
|
+
var RequestContextSchema = z.discriminatedUnion("request_type", [
|
|
30
|
+
HttpRequestContextSchema,
|
|
31
|
+
ActionRunContextSchema
|
|
32
|
+
]);
|
|
33
|
+
|
|
34
|
+
// src/constants.ts
|
|
35
|
+
var IGNORED_HEADERS = /* @__PURE__ */ new Set([
|
|
36
|
+
// Auth / credentials — never include in contexts or policy conditions
|
|
37
|
+
"authorization",
|
|
38
|
+
"x-relay-authorization",
|
|
39
|
+
"x-relay-authentication-id",
|
|
40
|
+
"x-api-key",
|
|
41
|
+
"cookie",
|
|
42
|
+
"set-cookie",
|
|
43
|
+
"proxy-authorization",
|
|
44
|
+
// HTTP infrastructure — varies per-request, not policy-relevant
|
|
45
|
+
"host",
|
|
46
|
+
"connection",
|
|
47
|
+
"content-length",
|
|
48
|
+
"transfer-encoding",
|
|
49
|
+
"accept-encoding",
|
|
50
|
+
"user-agent",
|
|
51
|
+
"accept",
|
|
52
|
+
"accept-language",
|
|
53
|
+
"sec-fetch-mode",
|
|
54
|
+
// Proxy / forwarding — infrastructure, not meaningful for policy
|
|
55
|
+
"x-forwarded-for",
|
|
56
|
+
"x-forwarded-host",
|
|
57
|
+
"x-forwarded-proto",
|
|
58
|
+
"x-real-ip",
|
|
59
|
+
// Proxy internal — sdkapi-specific headers
|
|
60
|
+
"x-is-interactive-session",
|
|
61
|
+
"x-relay-callback-url"
|
|
62
|
+
]);
|
|
63
|
+
|
|
64
|
+
// src/builders.ts
|
|
65
|
+
import { z as z2 } from "zod";
|
|
66
|
+
var BuildHttpRequestContextOptionsSchema = z2.object({
|
|
67
|
+
method: z2.string(),
|
|
68
|
+
/** Raw URL string. Will be normalized with https:// if no protocol present. */
|
|
69
|
+
url: z2.string(),
|
|
70
|
+
/** Raw headers from the request. Will be filtered through IGNORED_HEADERS. */
|
|
71
|
+
headers: z2.record(
|
|
72
|
+
z2.string(),
|
|
73
|
+
z2.union([z2.string(), z2.array(z2.string()), z2.undefined()])
|
|
74
|
+
).optional(),
|
|
75
|
+
/** Raw body string */
|
|
76
|
+
body: z2.string().nullable().optional(),
|
|
77
|
+
/** Pre-parsed JSON body (e.g. from Fastify's automatic JSON parsing) */
|
|
78
|
+
body_json: JsonValueSchema.optional(),
|
|
79
|
+
/** Connection ID associated with this request */
|
|
80
|
+
connection_id: z2.string().optional()
|
|
81
|
+
});
|
|
82
|
+
function buildHttpRequestContext(options) {
|
|
83
|
+
const url = options.url.includes("://") ? options.url : `https://${options.url}`;
|
|
84
|
+
const headers = {};
|
|
85
|
+
if (options.headers) {
|
|
86
|
+
for (const [key, value] of Object.entries(options.headers)) {
|
|
87
|
+
const lowerKey = key.toLowerCase();
|
|
88
|
+
if (!IGNORED_HEADERS.has(lowerKey) && typeof value === "string") {
|
|
89
|
+
headers[lowerKey] = value;
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
return HttpRequestContextSchema.parse({
|
|
94
|
+
request_type: "http_request",
|
|
95
|
+
method: options.method,
|
|
96
|
+
url,
|
|
97
|
+
headers,
|
|
98
|
+
body: typeof options.body === "string" ? options.body : void 0,
|
|
99
|
+
body_json: typeof options.body_json === "object" && options.body_json !== null ? options.body_json : void 0,
|
|
100
|
+
connection_id: options.connection_id
|
|
101
|
+
});
|
|
102
|
+
}
|
|
103
|
+
var BuildActionRunContextOptionsSchema = z2.object({
|
|
104
|
+
selected_api: z2.string(),
|
|
105
|
+
action_type: z2.string(),
|
|
106
|
+
action_key: z2.string(),
|
|
107
|
+
connection_id: z2.string().optional(),
|
|
108
|
+
inputs: JsonValueSchema.optional()
|
|
109
|
+
});
|
|
110
|
+
function buildActionRunContext(options) {
|
|
111
|
+
return ActionRunContextSchema.parse({
|
|
112
|
+
request_type: "action_run",
|
|
113
|
+
selected_api: options.selected_api,
|
|
114
|
+
action_type: options.action_type,
|
|
115
|
+
action_key: options.action_key,
|
|
116
|
+
connection_id: options.connection_id,
|
|
117
|
+
inputs: options.inputs
|
|
118
|
+
});
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
// src/conditions.ts
|
|
122
|
+
function buildExactHttpConditions(context) {
|
|
123
|
+
const conditions = [
|
|
124
|
+
{ path: ["method"], operator: "equals", value: context.method }
|
|
125
|
+
];
|
|
126
|
+
let parsedUrl;
|
|
127
|
+
try {
|
|
128
|
+
parsedUrl = new URL(context.url);
|
|
129
|
+
} catch {
|
|
130
|
+
console.debug(
|
|
131
|
+
"buildExactHttpConditions: unparseable URL, using raw value",
|
|
132
|
+
{ url: context.url }
|
|
133
|
+
);
|
|
134
|
+
conditions.push({
|
|
135
|
+
path: ["url"],
|
|
136
|
+
operator: "matches_url",
|
|
137
|
+
value: context.url
|
|
138
|
+
});
|
|
139
|
+
return conditions;
|
|
140
|
+
}
|
|
141
|
+
const urlWithoutQuery = `${parsedUrl.protocol}//${parsedUrl.host}${parsedUrl.pathname}`;
|
|
142
|
+
conditions.push({
|
|
143
|
+
path: ["url"],
|
|
144
|
+
operator: "matches_url",
|
|
145
|
+
value: urlWithoutQuery
|
|
146
|
+
});
|
|
147
|
+
const seenKeys = /* @__PURE__ */ new Set();
|
|
148
|
+
for (const key of parsedUrl.searchParams.keys()) {
|
|
149
|
+
if (seenKeys.has(key)) continue;
|
|
150
|
+
seenKeys.add(key);
|
|
151
|
+
const values = parsedUrl.searchParams.getAll(key);
|
|
152
|
+
conditions.push({
|
|
153
|
+
path: ["url", "query", key],
|
|
154
|
+
operator: "equals",
|
|
155
|
+
value: values
|
|
156
|
+
});
|
|
157
|
+
}
|
|
158
|
+
if (context.body_json !== void 0 && context.body_json !== null) {
|
|
159
|
+
conditions.push({
|
|
160
|
+
path: ["body_json"],
|
|
161
|
+
operator: "equals",
|
|
162
|
+
value: context.body_json
|
|
163
|
+
});
|
|
164
|
+
}
|
|
165
|
+
if (context.headers) {
|
|
166
|
+
for (const [key, value] of Object.entries(context.headers)) {
|
|
167
|
+
if (!IGNORED_HEADERS.has(key.toLowerCase()) && typeof value === "string") {
|
|
168
|
+
conditions.push({
|
|
169
|
+
path: ["headers", key.toLowerCase()],
|
|
170
|
+
operator: "equals",
|
|
171
|
+
value
|
|
172
|
+
});
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
}
|
|
176
|
+
return conditions;
|
|
177
|
+
}
|
|
178
|
+
function buildDomainHttpConditions(context) {
|
|
179
|
+
let host;
|
|
180
|
+
try {
|
|
181
|
+
host = new URL(context.url).host;
|
|
182
|
+
} catch {
|
|
183
|
+
return null;
|
|
184
|
+
}
|
|
185
|
+
return [
|
|
186
|
+
{
|
|
187
|
+
path: ["url", "host"],
|
|
188
|
+
operator: "matches_host",
|
|
189
|
+
value: host
|
|
190
|
+
}
|
|
191
|
+
];
|
|
192
|
+
}
|
|
193
|
+
function buildExactActionConditions(context) {
|
|
194
|
+
const conditions = [];
|
|
195
|
+
if (context.inputs !== void 0 && context.inputs !== null && typeof context.inputs === "object") {
|
|
196
|
+
conditions.push({
|
|
197
|
+
path: ["params"],
|
|
198
|
+
operator: "equals",
|
|
199
|
+
value: context.inputs
|
|
200
|
+
});
|
|
201
|
+
}
|
|
202
|
+
return conditions;
|
|
203
|
+
}
|
|
204
|
+
function buildActionResource(context) {
|
|
205
|
+
return `action/${context.selected_api}/${context.action_type}/${context.action_key}`;
|
|
206
|
+
}
|
|
207
|
+
function buildBroadActionResource(context) {
|
|
208
|
+
return `action/${context.selected_api}/*/*`;
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
// src/policies.ts
|
|
212
|
+
function buildAuthStatement(authenticationId) {
|
|
213
|
+
return {
|
|
214
|
+
effect: "allow",
|
|
215
|
+
permissions: ["can_use"],
|
|
216
|
+
resources: [`authentication/${authenticationId}`],
|
|
217
|
+
conditions: []
|
|
218
|
+
};
|
|
219
|
+
}
|
|
220
|
+
function httpContextToPolicy(context) {
|
|
221
|
+
const statements = [];
|
|
222
|
+
if (context.connection_id) {
|
|
223
|
+
statements.push(buildAuthStatement(context.connection_id));
|
|
224
|
+
}
|
|
225
|
+
const conditions = buildExactHttpConditions(context);
|
|
226
|
+
try {
|
|
227
|
+
const queryKeys = [...new URL(context.url).searchParams.keys()];
|
|
228
|
+
const uniqueKeys = [...new Set(queryKeys)];
|
|
229
|
+
conditions.push({
|
|
230
|
+
path: ["url", "query"],
|
|
231
|
+
operator: "keys_in",
|
|
232
|
+
value: uniqueKeys
|
|
233
|
+
});
|
|
234
|
+
} catch {
|
|
235
|
+
conditions.push({
|
|
236
|
+
path: ["url", "query"],
|
|
237
|
+
operator: "keys_in",
|
|
238
|
+
value: []
|
|
239
|
+
});
|
|
240
|
+
}
|
|
241
|
+
statements.push({
|
|
242
|
+
effect: "allow",
|
|
243
|
+
permissions: ["can_execute"],
|
|
244
|
+
resources: ["relay/http"],
|
|
245
|
+
conditions
|
|
246
|
+
});
|
|
247
|
+
return { version: 2, statements };
|
|
248
|
+
}
|
|
249
|
+
function actionContextToPolicy(context) {
|
|
250
|
+
const statements = [];
|
|
251
|
+
if (context.connection_id) {
|
|
252
|
+
statements.push(buildAuthStatement(context.connection_id));
|
|
253
|
+
}
|
|
254
|
+
statements.push({
|
|
255
|
+
effect: "allow",
|
|
256
|
+
permissions: ["can_execute"],
|
|
257
|
+
resources: [buildActionResource(context)],
|
|
258
|
+
conditions: buildExactActionConditions(context)
|
|
259
|
+
});
|
|
260
|
+
return { version: 2, statements };
|
|
261
|
+
}
|
|
262
|
+
function toExactPolicy(context) {
|
|
263
|
+
if (context.request_type === "http_request") {
|
|
264
|
+
return httpContextToPolicy(context);
|
|
265
|
+
}
|
|
266
|
+
return actionContextToPolicy(context);
|
|
267
|
+
}
|
|
268
|
+
export {
|
|
269
|
+
ActionRunContextSchema,
|
|
270
|
+
BuildActionRunContextOptionsSchema,
|
|
271
|
+
BuildHttpRequestContextOptionsSchema,
|
|
272
|
+
HttpRequestContextSchema,
|
|
273
|
+
IGNORED_HEADERS,
|
|
274
|
+
JsonValueSchema,
|
|
275
|
+
RequestContextSchema,
|
|
276
|
+
buildActionResource,
|
|
277
|
+
buildActionRunContext,
|
|
278
|
+
buildBroadActionResource,
|
|
279
|
+
buildDomainHttpConditions,
|
|
280
|
+
buildExactActionConditions,
|
|
281
|
+
buildExactHttpConditions,
|
|
282
|
+
buildHttpRequestContext,
|
|
283
|
+
toExactPolicy
|
|
284
|
+
};
|
|
285
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/types.ts","../src/constants.ts","../src/builders.ts","../src/conditions.ts","../src/policies.ts"],"sourcesContent":["// ABOUTME: Canonical request context types shared between sdkapi and approvalsapi.\n// ABOUTME: These define the contract for how requests are described in approval flows and policy evaluation.\n\nimport { z } from \"zod\";\nimport type { JsonValue } from \"@zapier/policy-schema\";\n\n/**\n * Zod schema for arbitrary JSON values. Used across context schemas for\n * unstructured fields like `body_json` and `inputs`.\n */\nexport const JsonValueSchema = z.custom<JsonValue>();\n\n/**\n * HTTP request context for approval/policy flows.\n * Sent by sdkapi when a relay request is denied, stored by approvalsapi,\n * and used to build policy conditions.\n */\nexport const HttpRequestContextSchema = z.object({\n request_type: z.literal(\"http_request\"),\n method: z.string(),\n /** Full URL including query string, e.g. \"https://api.example.com/v1/foo?bar=baz\" */\n url: z.string(),\n /** Filtered headers (IGNORED_HEADERS excluded, keys lowercased) */\n headers: z.record(z.string(), z.string()).optional(),\n /** Raw body string */\n body: z.string().optional(),\n /** Parsed JSON body */\n body_json: JsonValueSchema.optional(),\n /** Zapier connection ID used for this request */\n connection_id: z.string().optional(),\n /** Optional human-readable reason for the request */\n reason: z.string().optional(),\n});\nexport type HttpRequestContext = z.infer<typeof HttpRequestContextSchema>;\n\n/**\n * Action run context for approval/policy flows.\n * Sent by sdkapi when an action run is denied, stored by approvalsapi,\n * and used to build policy conditions.\n */\nexport const ActionRunContextSchema = z.object({\n request_type: z.literal(\"action_run\"),\n selected_api: z.string(),\n action_type: z.string(),\n action_key: z.string(),\n connection_id: z.string().optional(),\n inputs: JsonValueSchema.optional(),\n reason: z.string().optional(),\n});\nexport type ActionRunContext = z.infer<typeof ActionRunContextSchema>;\n\n/**\n * Discriminated union of all request context types.\n */\nexport const RequestContextSchema = z.discriminatedUnion(\"request_type\", [\n HttpRequestContextSchema,\n ActionRunContextSchema,\n]);\nexport type RequestContext = z.infer<typeof RequestContextSchema>;\n","// ABOUTME: Canonical set of headers to exclude when building request contexts.\n// ABOUTME: Shared between sdkapi (context creation) and approvalsapi (condition building).\n\n/**\n * Headers to exclude when building request contexts from raw HTTP requests.\n *\n * These are either sensitive (auth credentials), HTTP infrastructure headers\n * that vary per-request, or proxy-internal headers that are not meaningful\n * for policy decisions.\n */\nexport const IGNORED_HEADERS = new Set([\n // Auth / credentials — never include in contexts or policy conditions\n \"authorization\",\n \"x-relay-authorization\",\n \"x-relay-authentication-id\",\n \"x-api-key\",\n \"cookie\",\n \"set-cookie\",\n \"proxy-authorization\",\n\n // HTTP infrastructure — varies per-request, not policy-relevant\n \"host\",\n \"connection\",\n \"content-length\",\n \"transfer-encoding\",\n \"accept-encoding\",\n \"user-agent\",\n \"accept\",\n \"accept-language\",\n \"sec-fetch-mode\",\n\n // Proxy / forwarding — infrastructure, not meaningful for policy\n \"x-forwarded-for\",\n \"x-forwarded-host\",\n \"x-forwarded-proto\",\n \"x-real-ip\",\n\n // Proxy internal — sdkapi-specific headers\n \"x-is-interactive-session\",\n \"x-relay-callback-url\",\n]);\n","// ABOUTME: Canonical builders for creating request contexts from raw request parts.\n// ABOUTME: Used by sdkapi to build both approval contexts and policy eval contexts.\n\nimport { z } from \"zod\";\nimport {\n HttpRequestContextSchema,\n ActionRunContextSchema,\n JsonValueSchema,\n type HttpRequestContext,\n type ActionRunContext,\n} from \"./types.ts\";\nimport { IGNORED_HEADERS } from \"./constants.ts\";\n\nexport const BuildHttpRequestContextOptionsSchema = z.object({\n method: z.string(),\n /** Raw URL string. Will be normalized with https:// if no protocol present. */\n url: z.string(),\n /** Raw headers from the request. Will be filtered through IGNORED_HEADERS. */\n headers: z\n .record(\n z.string(),\n z.union([z.string(), z.array(z.string()), z.undefined()]),\n )\n .optional(),\n /** Raw body string */\n body: z.string().nullable().optional(),\n /** Pre-parsed JSON body (e.g. from Fastify's automatic JSON parsing) */\n body_json: JsonValueSchema.optional(),\n /** Connection ID associated with this request */\n connection_id: z.string().optional(),\n});\nexport type BuildHttpRequestContextOptions = z.infer<\n typeof BuildHttpRequestContextOptionsSchema\n>;\n\n/**\n * Build a canonical HttpRequestContext from raw request parts.\n *\n * This is the single source of truth for how HTTP request contexts are created.\n * Both sdkapi (for approval creation) and approvalsapi (for context storage)\n * should use this to ensure the context shape is consistent.\n *\n * - Normalizes URL (adds https:// if missing)\n * - Filters headers through IGNORED_HEADERS\n * - Only includes string-valued headers (drops string[] values like set-cookie)\n */\nexport function buildHttpRequestContext(\n options: BuildHttpRequestContextOptions,\n): HttpRequestContext {\n // Normalize URL — SDK CLI strips the protocol\n const url = options.url.includes(\"://\")\n ? options.url\n : `https://${options.url}`;\n\n // Filter headers: exclude ignored, lowercase keys, string values only\n const headers: Record<string, string> = {};\n if (options.headers) {\n for (const [key, value] of Object.entries(options.headers)) {\n const lowerKey = key.toLowerCase();\n if (!IGNORED_HEADERS.has(lowerKey) && typeof value === \"string\") {\n headers[lowerKey] = value;\n }\n }\n }\n\n return HttpRequestContextSchema.parse({\n request_type: \"http_request\",\n method: options.method,\n url,\n headers,\n body: typeof options.body === \"string\" ? options.body : undefined,\n body_json:\n typeof options.body_json === \"object\" && options.body_json !== null\n ? options.body_json\n : undefined,\n connection_id: options.connection_id,\n });\n}\n\nexport const BuildActionRunContextOptionsSchema = z.object({\n selected_api: z.string(),\n action_type: z.string(),\n action_key: z.string(),\n connection_id: z.string().optional(),\n inputs: JsonValueSchema.optional(),\n});\nexport type BuildActionRunContextOptions = z.infer<\n typeof BuildActionRunContextOptionsSchema\n>;\n\n/**\n * Build a canonical ActionRunContext from raw action parts.\n */\nexport function buildActionRunContext(\n options: BuildActionRunContextOptions,\n): ActionRunContext {\n return ActionRunContextSchema.parse({\n request_type: \"action_run\",\n selected_api: options.selected_api,\n action_type: options.action_type,\n action_key: options.action_key,\n connection_id: options.connection_id,\n inputs: options.inputs,\n });\n}\n","// ABOUTME: Builds policy conditions from stored request contexts.\n// ABOUTME: Used by approvalsapi's \"allow exact request\" and \"allow domain\" instant policy flows.\n\nimport type { Condition } from \"@zapier/policy-schema\";\nimport type { HttpRequestContext, ActionRunContext } from \"./types.ts\";\nimport { IGNORED_HEADERS } from \"./constants.ts\";\n\n/**\n * Build conditions that match an exact HTTP request.\n *\n * Handles the matches_url / query param split correctly:\n * - `matches_url` only supports scheme+host+port+path (no query string per spec)\n * - Query parameters are added as separate decomposed conditions on `url.query.<key>`\n *\n * @returns Condition[] for a relay/http permission statement\n */\nexport function buildExactHttpConditions(\n context: HttpRequestContext,\n): Condition[] {\n const conditions: Condition[] = [\n { path: [\"method\"], operator: \"equals\", value: context.method },\n ];\n\n // Parse the URL to separate path from query params\n let parsedUrl: URL;\n try {\n parsedUrl = new URL(context.url);\n } catch {\n // URL is unparseable — use it as-is (will fail matches_url, but that's correct)\n console.debug(\n \"buildExactHttpConditions: unparseable URL, using raw value\",\n { url: context.url },\n );\n conditions.push({\n path: [\"url\"],\n operator: \"matches_url\",\n value: context.url,\n });\n return conditions;\n }\n\n // matches_url condition uses URL without query string (per @zapier/policy spec)\n const urlWithoutQuery = `${parsedUrl.protocol}//${parsedUrl.host}${parsedUrl.pathname}`;\n conditions.push({\n path: [\"url\"],\n operator: \"matches_url\",\n value: urlWithoutQuery,\n });\n\n // Add decomposed conditions for each query parameter.\n // Use getAll to properly handle multi-value params (e.g. ?tag=a&tag=b → [\"a\", \"b\"]).\n const seenKeys = new Set<string>();\n for (const key of parsedUrl.searchParams.keys()) {\n if (seenKeys.has(key)) continue;\n seenKeys.add(key);\n const values = parsedUrl.searchParams.getAll(key);\n conditions.push({\n path: [\"url\", \"query\", key],\n operator: \"equals\",\n value: values,\n });\n }\n\n // body_json condition\n if (context.body_json !== undefined && context.body_json !== null) {\n conditions.push({\n path: [\"body_json\"],\n operator: \"equals\",\n value: context.body_json,\n });\n }\n\n // Header conditions (filtered through IGNORED_HEADERS again for safety)\n if (context.headers) {\n for (const [key, value] of Object.entries(context.headers)) {\n if (\n !IGNORED_HEADERS.has(key.toLowerCase()) &&\n typeof value === \"string\"\n ) {\n conditions.push({\n path: [\"headers\", key.toLowerCase()],\n operator: \"equals\",\n value,\n });\n }\n }\n }\n\n return conditions;\n}\n\n/**\n * Build conditions that match any request to a given domain.\n * Extracts the host from the context URL.\n *\n * @returns Condition[] for a relay/http permission statement, or null if URL is unparseable\n */\nexport function buildDomainHttpConditions(\n context: HttpRequestContext,\n): Condition[] | null {\n let host: string;\n try {\n host = new URL(context.url).host;\n } catch {\n return null;\n }\n\n return [\n {\n path: [\"url\", \"host\"],\n operator: \"matches_host\",\n value: host,\n },\n ];\n}\n\n/**\n * Build conditions that match an exact action run (with inputs).\n *\n * @returns Condition[] for an action permission statement\n */\nexport function buildExactActionConditions(\n context: ActionRunContext,\n): Condition[] {\n const conditions: Condition[] = [];\n\n if (\n context.inputs !== undefined &&\n context.inputs !== null &&\n typeof context.inputs === \"object\"\n ) {\n conditions.push({\n path: [\"params\"],\n operator: \"equals\",\n value: context.inputs,\n });\n }\n\n return conditions;\n}\n\n/**\n * Build the resource string for an action.\n * Format: action/{selected_api}/{action_type}/{action_key}\n */\nexport function buildActionResource(context: ActionRunContext): string {\n return `action/${context.selected_api}/${context.action_type}/${context.action_key}`;\n}\n\n/**\n * Build a broad action resource that matches all actions for an app.\n * Format: action/{selected_api}/{wildcard}/{wildcard}\n */\nexport function buildBroadActionResource(context: ActionRunContext): string {\n return `action/${context.selected_api}/*/*`;\n}\n","// ABOUTME: Assembles complete Policy objects from request contexts.\n// ABOUTME: Single source of truth for \"exact request\" instant policies used by web UI and API.\n\nimport type { Policy, Statement } from \"@zapier/policy-schema\";\nimport type {\n RequestContext,\n HttpRequestContext,\n ActionRunContext,\n} from \"./types.ts\";\nimport {\n buildExactHttpConditions,\n buildExactActionConditions,\n buildActionResource,\n} from \"./conditions.ts\";\n\n/**\n * Build a `can_use` authentication statement, if the context has a connection_id.\n */\nfunction buildAuthStatement(authenticationId: string): Statement {\n return {\n effect: \"allow\",\n permissions: [\"can_use\"],\n resources: [`authentication/${authenticationId}`],\n conditions: [],\n };\n}\n\n/**\n * Build an exact-match policy from an HTTP request context.\n *\n * Produces a policy that allows only the specific request described by the context:\n * - `can_use` statement for the authentication (if present)\n * - `can_execute` statement for `relay/http` with conditions from `buildExactHttpConditions`\n * plus a `keys_in` guard restricting allowed query parameter keys\n */\nfunction httpContextToPolicy(context: HttpRequestContext): Policy {\n const statements: Statement[] = [];\n\n if (context.connection_id) {\n statements.push(buildAuthStatement(context.connection_id));\n }\n\n const conditions = buildExactHttpConditions(context);\n\n // Add a keys_in guard so only the query param keys present in the original\n // request are allowed — blocks injection of extra query params.\n try {\n const queryKeys = [...new URL(context.url).searchParams.keys()];\n const uniqueKeys = [...new Set(queryKeys)];\n conditions.push({\n path: [\"url\", \"query\"],\n operator: \"keys_in\",\n value: uniqueKeys,\n });\n } catch {\n // If URL parsing fails, block all query params\n conditions.push({\n path: [\"url\", \"query\"],\n operator: \"keys_in\",\n value: [],\n });\n }\n\n statements.push({\n effect: \"allow\",\n permissions: [\"can_execute\"],\n resources: [\"relay/http\"],\n conditions,\n });\n\n return { version: 2, statements };\n}\n\n/**\n * Build an exact-match policy from an action run context.\n *\n * Produces a policy that allows only the specific action described by the context:\n * - `can_use` statement for the authentication (if present)\n * - `can_execute` statement for the action resource with input conditions\n */\nfunction actionContextToPolicy(context: ActionRunContext): Policy {\n const statements: Statement[] = [];\n\n if (context.connection_id) {\n statements.push(buildAuthStatement(context.connection_id));\n }\n\n statements.push({\n effect: \"allow\",\n permissions: [\"can_execute\"],\n resources: [buildActionResource(context)],\n conditions: buildExactActionConditions(context),\n });\n\n return { version: 2, statements };\n}\n\n/**\n * Build an exact-match policy from any supported request context.\n *\n * This is the single source of truth for \"allow this exact request\" instant policies.\n * Used by the web UI and anywhere else that needs to produce an exact policy from a context.\n */\nexport function toExactPolicy(context: RequestContext): Policy {\n if (context.request_type === \"http_request\") {\n return httpContextToPolicy(context);\n }\n return actionContextToPolicy(context);\n}\n"],"mappings":";AAGA,SAAS,SAAS;AAOX,IAAM,kBAAkB,EAAE,OAAkB;AAO5C,IAAM,2BAA2B,EAAE,OAAO;AAAA,EAC/C,cAAc,EAAE,QAAQ,cAAc;AAAA,EACtC,QAAQ,EAAE,OAAO;AAAA;AAAA,EAEjB,KAAK,EAAE,OAAO;AAAA;AAAA,EAEd,SAAS,EAAE,OAAO,EAAE,OAAO,GAAG,EAAE,OAAO,CAAC,EAAE,SAAS;AAAA;AAAA,EAEnD,MAAM,EAAE,OAAO,EAAE,SAAS;AAAA;AAAA,EAE1B,WAAW,gBAAgB,SAAS;AAAA;AAAA,EAEpC,eAAe,EAAE,OAAO,EAAE,SAAS;AAAA;AAAA,EAEnC,QAAQ,EAAE,OAAO,EAAE,SAAS;AAC9B,CAAC;AAQM,IAAM,yBAAyB,EAAE,OAAO;AAAA,EAC7C,cAAc,EAAE,QAAQ,YAAY;AAAA,EACpC,cAAc,EAAE,OAAO;AAAA,EACvB,aAAa,EAAE,OAAO;AAAA,EACtB,YAAY,EAAE,OAAO;AAAA,EACrB,eAAe,EAAE,OAAO,EAAE,SAAS;AAAA,EACnC,QAAQ,gBAAgB,SAAS;AAAA,EACjC,QAAQ,EAAE,OAAO,EAAE,SAAS;AAC9B,CAAC;AAMM,IAAM,uBAAuB,EAAE,mBAAmB,gBAAgB;AAAA,EACvE;AAAA,EACA;AACF,CAAC;;;AC/CM,IAAM,kBAAkB,oBAAI,IAAI;AAAA;AAAA,EAErC;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA;AAAA,EAGA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA;AAAA,EAGA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA;AAAA,EAGA;AAAA,EACA;AACF,CAAC;;;ACrCD,SAAS,KAAAA,UAAS;AAUX,IAAM,uCAAuCC,GAAE,OAAO;AAAA,EAC3D,QAAQA,GAAE,OAAO;AAAA;AAAA,EAEjB,KAAKA,GAAE,OAAO;AAAA;AAAA,EAEd,SAASA,GACN;AAAA,IACCA,GAAE,OAAO;AAAA,IACTA,GAAE,MAAM,CAACA,GAAE,OAAO,GAAGA,GAAE,MAAMA,GAAE,OAAO,CAAC,GAAGA,GAAE,UAAU,CAAC,CAAC;AAAA,EAC1D,EACC,SAAS;AAAA;AAAA,EAEZ,MAAMA,GAAE,OAAO,EAAE,SAAS,EAAE,SAAS;AAAA;AAAA,EAErC,WAAW,gBAAgB,SAAS;AAAA;AAAA,EAEpC,eAAeA,GAAE,OAAO,EAAE,SAAS;AACrC,CAAC;AAgBM,SAAS,wBACd,SACoB;AAEpB,QAAM,MAAM,QAAQ,IAAI,SAAS,KAAK,IAClC,QAAQ,MACR,WAAW,QAAQ,GAAG;AAG1B,QAAM,UAAkC,CAAC;AACzC,MAAI,QAAQ,SAAS;AACnB,eAAW,CAAC,KAAK,KAAK,KAAK,OAAO,QAAQ,QAAQ,OAAO,GAAG;AAC1D,YAAM,WAAW,IAAI,YAAY;AACjC,UAAI,CAAC,gBAAgB,IAAI,QAAQ,KAAK,OAAO,UAAU,UAAU;AAC/D,gBAAQ,QAAQ,IAAI;AAAA,MACtB;AAAA,IACF;AAAA,EACF;AAEA,SAAO,yBAAyB,MAAM;AAAA,IACpC,cAAc;AAAA,IACd,QAAQ,QAAQ;AAAA,IAChB;AAAA,IACA;AAAA,IACA,MAAM,OAAO,QAAQ,SAAS,WAAW,QAAQ,OAAO;AAAA,IACxD,WACE,OAAO,QAAQ,cAAc,YAAY,QAAQ,cAAc,OAC3D,QAAQ,YACR;AAAA,IACN,eAAe,QAAQ;AAAA,EACzB,CAAC;AACH;AAEO,IAAM,qCAAqCA,GAAE,OAAO;AAAA,EACzD,cAAcA,GAAE,OAAO;AAAA,EACvB,aAAaA,GAAE,OAAO;AAAA,EACtB,YAAYA,GAAE,OAAO;AAAA,EACrB,eAAeA,GAAE,OAAO,EAAE,SAAS;AAAA,EACnC,QAAQ,gBAAgB,SAAS;AACnC,CAAC;AAQM,SAAS,sBACd,SACkB;AAClB,SAAO,uBAAuB,MAAM;AAAA,IAClC,cAAc;AAAA,IACd,cAAc,QAAQ;AAAA,IACtB,aAAa,QAAQ;AAAA,IACrB,YAAY,QAAQ;AAAA,IACpB,eAAe,QAAQ;AAAA,IACvB,QAAQ,QAAQ;AAAA,EAClB,CAAC;AACH;;;ACxFO,SAAS,yBACd,SACa;AACb,QAAM,aAA0B;AAAA,IAC9B,EAAE,MAAM,CAAC,QAAQ,GAAG,UAAU,UAAU,OAAO,QAAQ,OAAO;AAAA,EAChE;AAGA,MAAI;AACJ,MAAI;AACF,gBAAY,IAAI,IAAI,QAAQ,GAAG;AAAA,EACjC,QAAQ;AAEN,YAAQ;AAAA,MACN;AAAA,MACA,EAAE,KAAK,QAAQ,IAAI;AAAA,IACrB;AACA,eAAW,KAAK;AAAA,MACd,MAAM,CAAC,KAAK;AAAA,MACZ,UAAU;AAAA,MACV,OAAO,QAAQ;AAAA,IACjB,CAAC;AACD,WAAO;AAAA,EACT;AAGA,QAAM,kBAAkB,GAAG,UAAU,QAAQ,KAAK,UAAU,IAAI,GAAG,UAAU,QAAQ;AACrF,aAAW,KAAK;AAAA,IACd,MAAM,CAAC,KAAK;AAAA,IACZ,UAAU;AAAA,IACV,OAAO;AAAA,EACT,CAAC;AAID,QAAM,WAAW,oBAAI,IAAY;AACjC,aAAW,OAAO,UAAU,aAAa,KAAK,GAAG;AAC/C,QAAI,SAAS,IAAI,GAAG,EAAG;AACvB,aAAS,IAAI,GAAG;AAChB,UAAM,SAAS,UAAU,aAAa,OAAO,GAAG;AAChD,eAAW,KAAK;AAAA,MACd,MAAM,CAAC,OAAO,SAAS,GAAG;AAAA,MAC1B,UAAU;AAAA,MACV,OAAO;AAAA,IACT,CAAC;AAAA,EACH;AAGA,MAAI,QAAQ,cAAc,UAAa,QAAQ,cAAc,MAAM;AACjE,eAAW,KAAK;AAAA,MACd,MAAM,CAAC,WAAW;AAAA,MAClB,UAAU;AAAA,MACV,OAAO,QAAQ;AAAA,IACjB,CAAC;AAAA,EACH;AAGA,MAAI,QAAQ,SAAS;AACnB,eAAW,CAAC,KAAK,KAAK,KAAK,OAAO,QAAQ,QAAQ,OAAO,GAAG;AAC1D,UACE,CAAC,gBAAgB,IAAI,IAAI,YAAY,CAAC,KACtC,OAAO,UAAU,UACjB;AACA,mBAAW,KAAK;AAAA,UACd,MAAM,CAAC,WAAW,IAAI,YAAY,CAAC;AAAA,UACnC,UAAU;AAAA,UACV;AAAA,QACF,CAAC;AAAA,MACH;AAAA,IACF;AAAA,EACF;AAEA,SAAO;AACT;AAQO,SAAS,0BACd,SACoB;AACpB,MAAI;AACJ,MAAI;AACF,WAAO,IAAI,IAAI,QAAQ,GAAG,EAAE;AAAA,EAC9B,QAAQ;AACN,WAAO;AAAA,EACT;AAEA,SAAO;AAAA,IACL;AAAA,MACE,MAAM,CAAC,OAAO,MAAM;AAAA,MACpB,UAAU;AAAA,MACV,OAAO;AAAA,IACT;AAAA,EACF;AACF;AAOO,SAAS,2BACd,SACa;AACb,QAAM,aAA0B,CAAC;AAEjC,MACE,QAAQ,WAAW,UACnB,QAAQ,WAAW,QACnB,OAAO,QAAQ,WAAW,UAC1B;AACA,eAAW,KAAK;AAAA,MACd,MAAM,CAAC,QAAQ;AAAA,MACf,UAAU;AAAA,MACV,OAAO,QAAQ;AAAA,IACjB,CAAC;AAAA,EACH;AAEA,SAAO;AACT;AAMO,SAAS,oBAAoB,SAAmC;AACrE,SAAO,UAAU,QAAQ,YAAY,IAAI,QAAQ,WAAW,IAAI,QAAQ,UAAU;AACpF;AAMO,SAAS,yBAAyB,SAAmC;AAC1E,SAAO,UAAU,QAAQ,YAAY;AACvC;;;ACzIA,SAAS,mBAAmB,kBAAqC;AAC/D,SAAO;AAAA,IACL,QAAQ;AAAA,IACR,aAAa,CAAC,SAAS;AAAA,IACvB,WAAW,CAAC,kBAAkB,gBAAgB,EAAE;AAAA,IAChD,YAAY,CAAC;AAAA,EACf;AACF;AAUA,SAAS,oBAAoB,SAAqC;AAChE,QAAM,aAA0B,CAAC;AAEjC,MAAI,QAAQ,eAAe;AACzB,eAAW,KAAK,mBAAmB,QAAQ,aAAa,CAAC;AAAA,EAC3D;AAEA,QAAM,aAAa,yBAAyB,OAAO;AAInD,MAAI;AACF,UAAM,YAAY,CAAC,GAAG,IAAI,IAAI,QAAQ,GAAG,EAAE,aAAa,KAAK,CAAC;AAC9D,UAAM,aAAa,CAAC,GAAG,IAAI,IAAI,SAAS,CAAC;AACzC,eAAW,KAAK;AAAA,MACd,MAAM,CAAC,OAAO,OAAO;AAAA,MACrB,UAAU;AAAA,MACV,OAAO;AAAA,IACT,CAAC;AAAA,EACH,QAAQ;AAEN,eAAW,KAAK;AAAA,MACd,MAAM,CAAC,OAAO,OAAO;AAAA,MACrB,UAAU;AAAA,MACV,OAAO,CAAC;AAAA,IACV,CAAC;AAAA,EACH;AAEA,aAAW,KAAK;AAAA,IACd,QAAQ;AAAA,IACR,aAAa,CAAC,aAAa;AAAA,IAC3B,WAAW,CAAC,YAAY;AAAA,IACxB;AAAA,EACF,CAAC;AAED,SAAO,EAAE,SAAS,GAAG,WAAW;AAClC;AASA,SAAS,sBAAsB,SAAmC;AAChE,QAAM,aAA0B,CAAC;AAEjC,MAAI,QAAQ,eAAe;AACzB,eAAW,KAAK,mBAAmB,QAAQ,aAAa,CAAC;AAAA,EAC3D;AAEA,aAAW,KAAK;AAAA,IACd,QAAQ;AAAA,IACR,aAAa,CAAC,aAAa;AAAA,IAC3B,WAAW,CAAC,oBAAoB,OAAO,CAAC;AAAA,IACxC,YAAY,2BAA2B,OAAO;AAAA,EAChD,CAAC;AAED,SAAO,EAAE,SAAS,GAAG,WAAW;AAClC;AAQO,SAAS,cAAc,SAAiC;AAC7D,MAAI,QAAQ,iBAAiB,gBAAgB;AAC3C,WAAO,oBAAoB,OAAO;AAAA,EACpC;AACA,SAAO,sBAAsB,OAAO;AACtC;","names":["z","z"]}
|
package/package.json
ADDED
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@zapier/policy-context",
|
|
3
|
+
"version": "0.3.0",
|
|
4
|
+
"description": "Shared request context types, builders, and policy condition generators for sdkapi and approvalsapi",
|
|
5
|
+
"repository": {
|
|
6
|
+
"type": "git",
|
|
7
|
+
"url": "https://gitlab.com/zapier/zapier-sdk/approvalsapi.git",
|
|
8
|
+
"directory": "packages/policy-context"
|
|
9
|
+
},
|
|
10
|
+
"type": "module",
|
|
11
|
+
"exports": {
|
|
12
|
+
".": "./src/index.ts",
|
|
13
|
+
"./*": "./src/*.ts"
|
|
14
|
+
},
|
|
15
|
+
"files": [
|
|
16
|
+
"dist"
|
|
17
|
+
],
|
|
18
|
+
"scripts": {
|
|
19
|
+
"build": "tsup",
|
|
20
|
+
"lint": "eslint src/**/*.ts",
|
|
21
|
+
"fmt": "prettier --write \"**/*.ts\"",
|
|
22
|
+
"test": "vitest run",
|
|
23
|
+
"test:watch": "vitest watch --clearScreen=false",
|
|
24
|
+
"types": "tsc",
|
|
25
|
+
"types:watch": "tsc --watch"
|
|
26
|
+
},
|
|
27
|
+
"publishConfig": {
|
|
28
|
+
"access": "restricted",
|
|
29
|
+
"provenance": true,
|
|
30
|
+
"main": "dist/index.cjs",
|
|
31
|
+
"module": "dist/index.js",
|
|
32
|
+
"types": "dist/index.d.ts",
|
|
33
|
+
"exports": {
|
|
34
|
+
".": {
|
|
35
|
+
"require": {
|
|
36
|
+
"types": "./dist/index.d.cts",
|
|
37
|
+
"default": "./dist/index.cjs"
|
|
38
|
+
},
|
|
39
|
+
"import": {
|
|
40
|
+
"types": "./dist/index.d.ts",
|
|
41
|
+
"default": "./dist/index.js"
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
},
|
|
46
|
+
"dependencies": {
|
|
47
|
+
"@zapier/policy-schema": "0.8.0",
|
|
48
|
+
"zod": "^4.0.0"
|
|
49
|
+
},
|
|
50
|
+
"devDependencies": {
|
|
51
|
+
"tsup": "^8.0.0"
|
|
52
|
+
}
|
|
53
|
+
}
|