@sequenceholdings/managed-functions 0.3.2 → 0.3.5

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.
@@ -0,0 +1,133 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __exportStar = (this && this.__exportStar) || function(m, exports) {
14
+ for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
15
+ };
16
+ Object.defineProperty(exports, "__esModule", { value: true });
17
+ exports.createFunctionServiceProcessesClient = createFunctionServiceProcessesClient;
18
+ const zod_1 = require("zod");
19
+ const processes_contract_1 = require("./processes-contract");
20
+ __exportStar(require("./processes-contract"), exports);
21
+ const invalidContext = () => new processes_contract_1.FunctionProcessReadError(401, 'invalid_context', 'This invocation has no valid process-read credential');
22
+ function readCredential({ request, }) {
23
+ const { headers } = request;
24
+ const matches = typeof headers.get === 'function'
25
+ ? [headers.get(processes_contract_1.FUNCTION_PROCESS_TOKEN_HEADER)]
26
+ : Object.entries(headers)
27
+ .filter(([name]) => name.toLowerCase() === processes_contract_1.FUNCTION_PROCESS_TOKEN_HEADER)
28
+ .map(([, value]) => value);
29
+ const token = matches[0];
30
+ if (matches.length !== 1 ||
31
+ typeof token !== 'string' ||
32
+ token.length > 16_384)
33
+ throw invalidContext();
34
+ const envelope = /^([A-Za-z0-9_-]+)\.([A-Za-z0-9_-]{43})$/.exec(token);
35
+ if (!envelope?.[1])
36
+ throw invalidContext();
37
+ let value;
38
+ try {
39
+ value = JSON.parse(Buffer.from(envelope[1], 'base64url').toString('utf8'));
40
+ }
41
+ catch {
42
+ throw invalidContext();
43
+ }
44
+ const parsed = zod_1.z
45
+ .object({
46
+ audience: zod_1.z.literal('atlas-managed-function-process-read'),
47
+ sub: zod_1.z.string().startsWith('service-account|'),
48
+ functionId: zod_1.z.string().min(1),
49
+ invocationId: zod_1.z.string().min(1),
50
+ exp: zod_1.z.number().int(),
51
+ })
52
+ .safeParse(value);
53
+ if (!parsed.success)
54
+ throw invalidContext();
55
+ return { token, expiresAt: parsed.data.exp };
56
+ }
57
+ function origin(baseUrl) {
58
+ let url;
59
+ try {
60
+ url = new URL(baseUrl);
61
+ }
62
+ catch {
63
+ throw new processes_contract_1.FunctionProcessReadError(400, 'invalid_configuration', 'Configure a trusted Atlas origin');
64
+ }
65
+ const loopback = url.protocol === 'http:' &&
66
+ ['localhost', '127.0.0.1', '[::1]'].includes(url.hostname);
67
+ if ((!loopback && url.protocol !== 'https:') ||
68
+ url.username ||
69
+ url.password ||
70
+ url.pathname !== '/' ||
71
+ url.search ||
72
+ url.hash) {
73
+ throw new processes_contract_1.FunctionProcessReadError(400, 'invalid_configuration', 'Configure an HTTPS Atlas origin without credentials, path, query or fragment');
74
+ }
75
+ return url.origin;
76
+ }
77
+ function createFunctionServiceProcessesClient({ request, baseUrl, fetchImpl = globalThis.fetch, }) {
78
+ const url = `${origin(baseUrl)}${processes_contract_1.FUNCTION_PROCESS_READ_PATH}`;
79
+ const { token, expiresAt } = readCredential({ request });
80
+ async function read({ body, schema, }) {
81
+ if (expiresAt <= Date.now() / 1000)
82
+ throw new processes_contract_1.FunctionProcessReadError(401, 'expired_context', 'The process-read credential expired; start a new invocation');
83
+ const parsed = processes_contract_1.functionProcessReadRequestSchema.parse(body);
84
+ const response = await fetchImpl(url, {
85
+ method: 'POST',
86
+ headers: {
87
+ 'content-type': 'application/json',
88
+ [processes_contract_1.FUNCTION_PROCESS_TOKEN_HEADER]: token,
89
+ },
90
+ body: JSON.stringify(parsed),
91
+ redirect: 'error',
92
+ signal: AbortSignal.timeout(30_000),
93
+ });
94
+ const result = await response.json().catch(() => null);
95
+ if (!response.ok) {
96
+ const error = zod_1.z
97
+ .object({
98
+ code: zod_1.z.string().max(128).optional(),
99
+ detail: zod_1.z.string().max(2000).optional(),
100
+ })
101
+ .safeParse(result);
102
+ throw new processes_contract_1.FunctionProcessReadError(response.status, error.success
103
+ ? (error.data.code ?? 'process_read_failed')
104
+ : 'process_read_failed', error.success
105
+ ? (error.data.detail ?? 'Process read failed')
106
+ : 'Process read failed');
107
+ }
108
+ const validated = schema.safeParse(result);
109
+ if (!validated.success)
110
+ throw new processes_contract_1.FunctionProcessReadError(502, 'malformed_response', 'Atlas returned an invalid process-read response');
111
+ return validated.data;
112
+ }
113
+ return {
114
+ async getRun(query) {
115
+ const run = await read({
116
+ body: { ...query, operation: 'getRun' },
117
+ schema: processes_contract_1.functionProcessRunSummarySchema,
118
+ });
119
+ if (run.id !== query.runId || run.processId !== query.process)
120
+ throw new processes_contract_1.FunctionProcessReadError(502, 'malformed_response', 'Atlas returned a different process run');
121
+ return run;
122
+ },
123
+ async listRunsPage(query) {
124
+ const page = await read({
125
+ body: { ...query, operation: 'listRunsPage' },
126
+ schema: processes_contract_1.functionProcessRunsPageSchema,
127
+ });
128
+ if (page.runs.some((run) => run.processId !== query.process))
129
+ throw new processes_contract_1.FunctionProcessReadError(502, 'malformed_response', 'Atlas returned runs from a different process');
130
+ return page;
131
+ },
132
+ };
133
+ }