@sequenceholdings/managed-functions 0.4.2 → 0.4.4
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/README.md +86 -2
- package/dist/capabilities.d.ts +28 -0
- package/dist/capabilities.js +6 -0
- package/dist/config.d.ts +2 -1
- package/dist/config.js +5 -2
- package/dist/deployed-policy.js +9 -2
- package/dist/directory-manifest.d.ts +1 -0
- package/dist/directory-manifest.js +3 -1
- package/dist/directory-roster-contract.d.ts +22 -0
- package/dist/directory-roster-contract.js +24 -0
- package/dist/index.d.ts +4 -1
- package/dist/index.js +4 -1
- package/dist/invocation-contract.d.ts +25 -2
- package/dist/invocation-contract.js +21 -6
- package/dist/invocation.d.ts +2 -1
- package/dist/invocation.js +48 -38
- package/dist/lattice-provenance-contract.d.ts +88 -0
- package/dist/lattice-provenance-contract.js +10 -1
- package/dist/lattice-provenance.d.ts +2 -1
- package/dist/lattice-provenance.js +3 -0
- package/dist/monitoring-contract.d.ts +2 -2
- package/dist/monitoring-contract.js +2 -2
- package/dist/orm.d.ts +4 -1
- package/dist/preflight-invocation.js +31 -5
- package/dist/preflight-service-directory-roster.d.ts +2 -0
- package/dist/preflight-service-directory-roster.js +17 -0
- package/dist/preflight.js +3 -0
- package/dist/processes-contract.d.ts +20 -0
- package/dist/processes-contract.js +7 -1
- package/dist/processes.d.ts +2 -1
- package/dist/processes.js +6 -0
- package/dist/runtime.cjs +217 -46
- package/dist/service-directory-roster.d.ts +7 -0
- package/dist/service-directory-roster.js +25 -0
- package/dist/service-directory.d.ts +2 -0
- package/dist/service-directory.js +2 -0
- package/package.json +3 -3
package/README.md
CHANGED
|
@@ -324,6 +324,20 @@ const page = await processes.listRunsPage({
|
|
|
324
324
|
})
|
|
325
325
|
```
|
|
326
326
|
|
|
327
|
+
The SDK 0.4.4 / CLI 0.6.6 release candidates (awaiting publication) add
|
|
328
|
+
`processes.getCompletedNode({ process, runId, nodeId })`. It returns only
|
|
329
|
+
`{ runId, processId, processVersion, nodeId, stepId, completedAt }` after both
|
|
330
|
+
the run and its latest top-level step have committed successfully. The exact
|
|
331
|
+
node must have no outgoing edges in the run's immutable pinned bundle. The
|
|
332
|
+
existing invocation-bound process scope and current Process/Run Viewer grants
|
|
333
|
+
apply. Historical successful steps in running, cancelled or failed runs,
|
|
334
|
+
parallel child steps, and ambiguous serial positions are refused with
|
|
335
|
+
`409 node_not_completed`; workers can retry without sending their side effect.
|
|
336
|
+
The caller must separately check its expected process version and allowed
|
|
337
|
+
terminal node. No authored metadata, state or output is exposed. This method
|
|
338
|
+
requires the matching server deployment; the older `processes_read` capability
|
|
339
|
+
alone does not advertise support for this new operation.
|
|
340
|
+
|
|
327
341
|
With SDK 0.4.2 and both exact process and agent read declarations,
|
|
328
342
|
`processes.getCompletedAgentReference({ process, runId, nodeId })` recovers only
|
|
329
343
|
`{ stepId, attempt, agentId, agentRunId, threadId }` for a unique completed
|
|
@@ -451,6 +465,21 @@ const invocation = createFunctionInvocationClient({ request, baseUrl: platformOr
|
|
|
451
465
|
const { receiver, caller } = await invocation.getInvocationContext()
|
|
452
466
|
```
|
|
453
467
|
|
|
468
|
+
With `capabilities.invocation: { identity: true, caller_capabilities: true }`,
|
|
469
|
+
`invocation.getCallerCapabilities()` returns `{ receiver, caller, capabilities }`.
|
|
470
|
+
It accepts no subject or host selector. Atlas rechecks the exact live invocation,
|
|
471
|
+
receiver/version and current human caller, resolves that caller's function
|
|
472
|
+
access and custom-role grants, and intersects the result with the receiver's
|
|
473
|
+
current declared capability vocabulary (at most 256 pins). Service/system
|
|
474
|
+
callers are refused; this method cannot borrow a run starter or attached
|
|
475
|
+
service account's grants. Revoked or undeclared grants are absent, and failures
|
|
476
|
+
never supply capability authority. It does not accept unsigned claim headers.
|
|
477
|
+
|
|
478
|
+
This opt-in requires deployed `invocation_caller_capabilities` support, SDK
|
|
479
|
+
0.4.4 and CLI 0.6.6. Identity-only manifests retain their previous behavior.
|
|
480
|
+
Do not cache this current observation as a lasting grant or expose the
|
|
481
|
+
invocation credential to a browser.
|
|
482
|
+
|
|
454
483
|
The receiver identifies this function, version, invocation, organization and
|
|
455
484
|
attached service account. The caller is the authenticated human, service
|
|
456
485
|
account or system principal that invoked it; the attached account and a
|
|
@@ -506,6 +535,16 @@ or context metadata are never substitutes. Older runs may omit this field or
|
|
|
506
535
|
return `null`. A start stamp records the original admission decision, rather
|
|
507
536
|
than granting current permissions or identifying a later human action.
|
|
508
537
|
|
|
538
|
+
`getRunCreatorAccess()` returns current, invocation-bound evidence for the
|
|
539
|
+
retained signed run starter: `{ creator: { sub, tenant, platformOperator } | null,
|
|
540
|
+
observedAt, ...executionIdentity }`. The platform resolves a current active human
|
|
541
|
+
and evaluates its shared operator policy; app-authored metadata and email domains
|
|
542
|
+
cannot establish this authority. Missing provenance, deleted/disabled identities,
|
|
543
|
+
or ambiguous aliases return `creator: null`; directory outages fail the request.
|
|
544
|
+
Operator evaluation retains the shared platform policy, including its FGA cache
|
|
545
|
+
and configured legacy-role fallback; this is not instantaneous role revocation. This is a current observation, not an impersonation credential or a
|
|
546
|
+
replacement for business authorization. It accepts no subject or run selector.
|
|
547
|
+
|
|
509
548
|
Human reads verify a platform-signed receipt against the actual completed step,
|
|
510
549
|
current receiving invocation, frozen graph and causal subprocess lineage. The
|
|
511
550
|
caller must still check the expected action, task, approval generation and
|
|
@@ -583,7 +622,7 @@ capabilities:
|
|
|
583
622
|
```
|
|
584
623
|
|
|
585
624
|
Declarations grant no monitoring authority. The attached account needs the
|
|
586
|
-
producer namespace's runtime floor and pinned `
|
|
625
|
+
producer namespace's runtime floor and pinned `emit-monitoring` capability.
|
|
587
626
|
Continuous Improvement must also register that exact namespace and authorize
|
|
588
627
|
publishing or catalog reads. Registrations default to inactive with both
|
|
589
628
|
operations disabled. Only a human with current Monitoring Admin authority can
|
|
@@ -627,7 +666,7 @@ accepted. A legitimate zero-event result still receives a hash-bound receipt.
|
|
|
627
666
|
Both publishing and lookup require producer authorization.
|
|
628
667
|
|
|
629
668
|
`getBucketCatalog({ producer })` reads only the complete active taxonomy
|
|
630
|
-
metadata under the separate namespace `
|
|
669
|
+
metadata under the separate namespace `read-monitoring-catalog` capability.
|
|
631
670
|
Freeze that catalog with the analysis inputs. More than 2000 buckets or 512 KiB
|
|
632
671
|
returns an explicit size error; the client never treats a partial catalog as complete.
|
|
633
672
|
|
|
@@ -770,3 +809,48 @@ Successful reads of a Lattice process or run link to the owning process; direct
|
|
|
770
809
|
HTTP run starts already use server-recorded spans and preserve the request chain.
|
|
771
810
|
Transport classification is shared with the platform host; function authors
|
|
772
811
|
do not need to import or configure instrumentation.
|
|
812
|
+
|
|
813
|
+
## Scoped service group rosters
|
|
814
|
+
|
|
815
|
+
`createFunctionServiceDirectoryClient().listGroupMembers()` reads bounded pages
|
|
816
|
+
of active members of explicitly declared groups. It requires Managed Functions
|
|
817
|
+
SDK 0.4.4, Studio CLI 0.6.6, and a host advertising `directory_rosters`.
|
|
818
|
+
|
|
819
|
+
```yaml
|
|
820
|
+
service_account: notification-worker
|
|
821
|
+
capabilities:
|
|
822
|
+
directory:
|
|
823
|
+
resolve: [banksouth]
|
|
824
|
+
rosters: ["11111111-1111-4111-8111-111111111111"]
|
|
825
|
+
```
|
|
826
|
+
|
|
827
|
+
```ts
|
|
828
|
+
const directory = createFunctionServiceDirectoryClient({ request, baseUrl })
|
|
829
|
+
let cursor: string | undefined
|
|
830
|
+
do {
|
|
831
|
+
const page = await directory.listGroupMembers({
|
|
832
|
+
tenant: 'banksouth', groupId, limit: 50, cursor,
|
|
833
|
+
})
|
|
834
|
+
await consume(page.members)
|
|
835
|
+
cursor = page.nextCursor ?? undefined
|
|
836
|
+
} while (cursor)
|
|
837
|
+
```
|
|
838
|
+
|
|
839
|
+
The manifest permits at most 16 concrete group IDs. It does not grant access:
|
|
840
|
+
the attached service account independently needs the tenant directory's Reader
|
|
841
|
+
relation and the group's Member relation (direct membership or the group's Owner
|
|
842
|
+
relation). Organization or application administration is not a fallback. The
|
|
843
|
+
actual attached account is checked on every page; the invoking human/system
|
|
844
|
+
identity never supplies its grants. No user-mode directory API gains service mode.
|
|
845
|
+
|
|
846
|
+
Atlas intersects the signed invocation's groups with the current function
|
|
847
|
+
manifest, verifies the live function/version/account/invocation, and checks both
|
|
848
|
+
grants again before reading. Deleted groups and inactive, deleted, or foreign
|
|
849
|
+
tenant users are excluded. The caller cannot request inactive identities or
|
|
850
|
+
choose another principal. Results contain only `id`, `sub`, `name`, `email`, and
|
|
851
|
+
`deactivated: false`. Membership is read live, not as a transaction-wide snapshot.
|
|
852
|
+
|
|
853
|
+
Pagination scans membership positions, so a page may have zero members and a
|
|
854
|
+
non-null `nextCursor`; continue until the cursor is null. Cursors expire after an
|
|
855
|
+
hour and bind the tenant, group, function, immutable version and service account.
|
|
856
|
+
They cannot be moved to another read scope. Access can be revoked between pages.
|
package/dist/capabilities.d.ts
CHANGED
|
@@ -13,6 +13,13 @@ export declare const MANAGED_FUNCTION_CAPABILITIES: {
|
|
|
13
13
|
};
|
|
14
14
|
};
|
|
15
15
|
readonly features: {
|
|
16
|
+
readonly directory_rosters: {
|
|
17
|
+
readonly field: "capabilities.directory.rosters";
|
|
18
|
+
readonly supported: true;
|
|
19
|
+
readonly limit: "1 to 16 explicit groups; up to 50 active tenant members per page; directory Reader and group membership required";
|
|
20
|
+
readonly min_cli: "0.6.6";
|
|
21
|
+
readonly min_sdk: "0.4.4";
|
|
22
|
+
};
|
|
16
23
|
readonly directory_members: {
|
|
17
24
|
readonly field: "capabilities.directory.groups";
|
|
18
25
|
readonly supported: true;
|
|
@@ -34,6 +41,13 @@ export declare const MANAGED_FUNCTION_CAPABILITIES: {
|
|
|
34
41
|
readonly min_cli: "0.5.5";
|
|
35
42
|
readonly min_sdk: "0.4.2";
|
|
36
43
|
};
|
|
44
|
+
readonly invocation_caller_capabilities: {
|
|
45
|
+
readonly field: "capabilities.invocation.caller_capabilities";
|
|
46
|
+
readonly supported: true;
|
|
47
|
+
readonly limit: "current human caller capabilities declared by this exact active receiver; at most 256 pins";
|
|
48
|
+
readonly min_cli: "0.6.6";
|
|
49
|
+
readonly min_sdk: "0.4.4";
|
|
50
|
+
};
|
|
37
51
|
readonly invocation_identity: {
|
|
38
52
|
readonly field: "capabilities.invocation.identity";
|
|
39
53
|
readonly supported: true;
|
|
@@ -134,6 +148,13 @@ export interface CapabilityTooling {
|
|
|
134
148
|
export interface ManagedFunctionCapabilities {
|
|
135
149
|
tooling: CapabilityTooling;
|
|
136
150
|
features: {
|
|
151
|
+
directory_rosters?: {
|
|
152
|
+
field: string;
|
|
153
|
+
supported: boolean;
|
|
154
|
+
limit: string;
|
|
155
|
+
min_cli: string;
|
|
156
|
+
min_sdk: string;
|
|
157
|
+
};
|
|
137
158
|
directory_members?: {
|
|
138
159
|
field: string;
|
|
139
160
|
supported: boolean;
|
|
@@ -155,6 +176,13 @@ export interface ManagedFunctionCapabilities {
|
|
|
155
176
|
min_cli: string;
|
|
156
177
|
min_sdk: string;
|
|
157
178
|
};
|
|
179
|
+
invocation_caller_capabilities?: {
|
|
180
|
+
field: string;
|
|
181
|
+
supported: boolean;
|
|
182
|
+
limit: string;
|
|
183
|
+
min_cli: string;
|
|
184
|
+
min_sdk: string;
|
|
185
|
+
};
|
|
158
186
|
invocation_identity?: {
|
|
159
187
|
field: string;
|
|
160
188
|
supported: boolean;
|
package/dist/capabilities.js
CHANGED
|
@@ -16,6 +16,7 @@ exports.MANAGED_FUNCTION_CAPABILITIES = {
|
|
|
16
16
|
sdk: { package: exports.MANAGED_FUNCTION_SDK_PACKAGE, min: '0.3.0' },
|
|
17
17
|
},
|
|
18
18
|
features: {
|
|
19
|
+
directory_rosters: { field: 'capabilities.directory.rosters', supported: true, limit: '1 to 16 explicit groups; up to 50 active tenant members per page; directory Reader and group membership required', min_cli: '0.6.6', min_sdk: '0.4.4' },
|
|
19
20
|
directory_members: {
|
|
20
21
|
field: 'capabilities.directory.groups', supported: true,
|
|
21
22
|
limit: '1 to 16 concrete groups; resolve 1 to 50 selected active members per call',
|
|
@@ -31,6 +32,11 @@ exports.MANAGED_FUNCTION_CAPABILITIES = {
|
|
|
31
32
|
limit: 'a fresh function identity whose runtime cannot be redeployed after first activation',
|
|
32
33
|
min_cli: '0.5.5', min_sdk: '0.4.2',
|
|
33
34
|
},
|
|
35
|
+
invocation_caller_capabilities: {
|
|
36
|
+
field: 'capabilities.invocation.caller_capabilities', supported: true,
|
|
37
|
+
limit: 'current human caller capabilities declared by this exact active receiver; at most 256 pins',
|
|
38
|
+
min_cli: '0.6.6', min_sdk: '0.4.4',
|
|
39
|
+
},
|
|
34
40
|
invocation_identity: {
|
|
35
41
|
field: 'capabilities.invocation.identity', supported: true,
|
|
36
42
|
limit: 'verified receiver and actual caller for this exact active invocation only',
|
package/dist/config.d.ts
CHANGED
|
@@ -2,7 +2,7 @@ export { DIRECTORY_TOKEN_HEADER, directoryGroupIdSchema, directoryScopesSchema,
|
|
|
2
2
|
export { functionDirectoryManifestSchema } from './directory-manifest';
|
|
3
3
|
export { functionLatticeContextCapabilitySchema, readFunctionLatticeContextCapability } from './lattice-capability';
|
|
4
4
|
export * from './invocation-contract';
|
|
5
|
-
export { FUNCTION_PROCESS_TOKEN_HEADER, FUNCTION_PROCESS_READ_PATH, functionProcessReadScopesSchema, readFunctionProcessScopes, functionProcessReadRequestSchema, functionProcessRunSummarySchema, functionProcessCompletedAgentReferenceSchema, functionProcessCompletedAgentReferenceQuerySchema } from './processes-contract';
|
|
5
|
+
export { FUNCTION_PROCESS_TOKEN_HEADER, FUNCTION_PROCESS_READ_PATH, functionProcessReadScopesSchema, readFunctionProcessScopes, functionProcessReadRequestSchema, functionProcessRunSummarySchema, functionProcessCompletedAgentReferenceSchema, functionProcessCompletedAgentReferenceQuerySchema, functionProcessCompletedNodeSchema, functionProcessCompletedNodeQuerySchema } from './processes-contract';
|
|
6
6
|
export { FUNCTION_AGENT_TOKEN_HEADER, FUNCTION_AGENT_READ_PATH, functionAgentReadScopesSchema, readFunctionAgentScopes, functionAgentReadRequestSchema, functionAgentCompletedRunQuerySchema, functionAgentCompletedRunSchema } from './agents-contract';
|
|
7
7
|
export * from './agent-source-evidence-contract';
|
|
8
8
|
export * from './workflow-source-contract';
|
|
@@ -36,3 +36,4 @@ export declare const cacheManifestSchema: z.ZodObject<{
|
|
|
36
36
|
}, z.core.$strict>;
|
|
37
37
|
export type CacheConfiguration = z.infer<typeof cacheManifestSchema>;
|
|
38
38
|
export declare function readCacheConfiguration(manifest: unknown): CacheConfiguration;
|
|
39
|
+
export * from './directory-roster-contract';
|
package/dist/config.js
CHANGED
|
@@ -14,8 +14,8 @@ var __exportStar = (this && this.__exportStar) || function(m, exports) {
|
|
|
14
14
|
for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
|
|
15
15
|
};
|
|
16
16
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
17
|
-
exports.
|
|
18
|
-
exports.cacheManifestSchema = exports.CACHE_MAX_TTL_SECONDS = exports.preflightManagedFunction = exports.parseDeployedPolicy = void 0;
|
|
17
|
+
exports.sdkSpecFromPackageJson = exports.sdkVersionFromPackageJson = exports.isPostgresEgress = exports.formatValidationDetail = exports.MANAGED_FUNCTION_SDK_PACKAGE = exports.MANAGED_FUNCTION_CLI_PACKAGE = exports.MANAGED_FUNCTION_CAPABILITIES = exports.managedFunctionWorkloadLimitsSchema = exports.MF_LIMITS_DEFAULTS = exports.MF_LIMITS_CAPS = exports.MANAGED_FUNCTION_LIMITS = exports.readFunctionImmutableRelease = exports.functionImmutableReleaseSchema = exports.shouldReportAtlasHttp = exports.directoryPrincipalResolutionSchema = exports.directoryPrincipalResolveRequestSchema = exports.readFunctionDirectoryScopes = exports.functionDirectoryScopesSchema = exports.FUNCTION_DIRECTORY_RESOLVE_PATH = exports.FUNCTION_DIRECTORY_TOKEN_HEADER = exports.FUNCTION_CALLER_DATA_TOKEN_HEADER = exports.readFunctionWorkflowEvidenceScopes = exports.readFunctionWorkflowScopes = exports.functionWorkflowScopesSchema = exports.functionAgentCompletedRunSchema = exports.functionAgentCompletedRunQuerySchema = exports.functionAgentReadRequestSchema = exports.readFunctionAgentScopes = exports.functionAgentReadScopesSchema = exports.FUNCTION_AGENT_READ_PATH = exports.FUNCTION_AGENT_TOKEN_HEADER = exports.functionProcessCompletedNodeQuerySchema = exports.functionProcessCompletedNodeSchema = exports.functionProcessCompletedAgentReferenceQuerySchema = exports.functionProcessCompletedAgentReferenceSchema = exports.functionProcessRunSummarySchema = exports.functionProcessReadRequestSchema = exports.readFunctionProcessScopes = exports.functionProcessReadScopesSchema = exports.FUNCTION_PROCESS_READ_PATH = exports.FUNCTION_PROCESS_TOKEN_HEADER = exports.readFunctionLatticeContextCapability = exports.functionLatticeContextCapabilitySchema = exports.functionDirectoryManifestSchema = exports.readDirectoryGroups = exports.directoryMembersResponse = exports.directoryMembersInput = exports.directoryScopesSchema = exports.directoryGroupIdSchema = exports.DIRECTORY_TOKEN_HEADER = void 0;
|
|
18
|
+
exports.cacheManifestSchema = exports.CACHE_MAX_TTL_SECONDS = exports.preflightManagedFunction = exports.parseDeployedPolicy = exports.versionIsOlder = exports.sdkVersionLowerBound = void 0;
|
|
19
19
|
exports.readCacheConfiguration = readCacheConfiguration;
|
|
20
20
|
var directory_config_1 = require("./directory-config");
|
|
21
21
|
Object.defineProperty(exports, "DIRECTORY_TOKEN_HEADER", { enumerable: true, get: function () { return directory_config_1.DIRECTORY_TOKEN_HEADER; } });
|
|
@@ -39,6 +39,8 @@ Object.defineProperty(exports, "functionProcessReadRequestSchema", { enumerable:
|
|
|
39
39
|
Object.defineProperty(exports, "functionProcessRunSummarySchema", { enumerable: true, get: function () { return processes_contract_1.functionProcessRunSummarySchema; } });
|
|
40
40
|
Object.defineProperty(exports, "functionProcessCompletedAgentReferenceSchema", { enumerable: true, get: function () { return processes_contract_1.functionProcessCompletedAgentReferenceSchema; } });
|
|
41
41
|
Object.defineProperty(exports, "functionProcessCompletedAgentReferenceQuerySchema", { enumerable: true, get: function () { return processes_contract_1.functionProcessCompletedAgentReferenceQuerySchema; } });
|
|
42
|
+
Object.defineProperty(exports, "functionProcessCompletedNodeSchema", { enumerable: true, get: function () { return processes_contract_1.functionProcessCompletedNodeSchema; } });
|
|
43
|
+
Object.defineProperty(exports, "functionProcessCompletedNodeQuerySchema", { enumerable: true, get: function () { return processes_contract_1.functionProcessCompletedNodeQuerySchema; } });
|
|
42
44
|
var agents_contract_1 = require("./agents-contract");
|
|
43
45
|
Object.defineProperty(exports, "FUNCTION_AGENT_TOKEN_HEADER", { enumerable: true, get: function () { return agents_contract_1.FUNCTION_AGENT_TOKEN_HEADER; } });
|
|
44
46
|
Object.defineProperty(exports, "FUNCTION_AGENT_READ_PATH", { enumerable: true, get: function () { return agents_contract_1.FUNCTION_AGENT_READ_PATH; } });
|
|
@@ -115,3 +117,4 @@ function readCacheConfiguration(manifest) {
|
|
|
115
117
|
: undefined;
|
|
116
118
|
return exports.cacheManifestSchema.parse(cache ?? {});
|
|
117
119
|
}
|
|
120
|
+
__exportStar(require("./directory-roster-contract"), exports);
|
package/dist/deployed-policy.js
CHANGED
|
@@ -40,8 +40,10 @@ function normalizeCapabilities(value) {
|
|
|
40
40
|
features: {
|
|
41
41
|
immutable_release: normalizeImmutableRelease(features.immutable_release),
|
|
42
42
|
invocation_identity: normalizeInvocationIdentity(features.invocation_identity),
|
|
43
|
+
invocation_caller_capabilities: normalizeInvocationIdentity(features.invocation_caller_capabilities, 'capabilities.invocation.caller_capabilities'),
|
|
43
44
|
directory_members: normalizeDirectoryMembers(features.directory_members),
|
|
44
45
|
directory_resolve: normalizeDirectory(features.directory_resolve),
|
|
46
|
+
directory_rosters: normalizeRosters(features.directory_rosters),
|
|
45
47
|
abrigo_read: normalizeAbrigo(features.abrigo_read),
|
|
46
48
|
lattice_context: normalizeLatticeContext(features.lattice_context),
|
|
47
49
|
postgres_egress: normalizePostgres(features.postgres_egress),
|
|
@@ -89,13 +91,13 @@ function normalizeAbrigo(value) {
|
|
|
89
91
|
return undefined;
|
|
90
92
|
return { field: typeof value.field === 'string' ? value.field : 'capabilities.abrigo.read', supported: value.supported, limit: value.limit, min_cli: value.min_cli, min_sdk: value.min_sdk };
|
|
91
93
|
}
|
|
92
|
-
function normalizeInvocationIdentity(value) {
|
|
94
|
+
function normalizeInvocationIdentity(value, defaultField = 'capabilities.invocation.identity') {
|
|
93
95
|
if (!value || typeof value.supported !== 'boolean' || typeof value.limit !== 'string')
|
|
94
96
|
return undefined;
|
|
95
97
|
if (typeof value.min_cli !== 'string' || typeof value.min_sdk !== 'string')
|
|
96
98
|
return undefined;
|
|
97
99
|
return {
|
|
98
|
-
field: typeof value.field === 'string' ? value.field :
|
|
100
|
+
field: typeof value.field === 'string' ? value.field : defaultField,
|
|
99
101
|
supported: value.supported, limit: value.limit, min_cli: value.min_cli, min_sdk: value.min_sdk,
|
|
100
102
|
};
|
|
101
103
|
}
|
|
@@ -202,3 +204,8 @@ function normalizeTimeout(value) {
|
|
|
202
204
|
min_sdk: value.min_sdk,
|
|
203
205
|
};
|
|
204
206
|
}
|
|
207
|
+
function normalizeRosters(value) {
|
|
208
|
+
if (!value || typeof value.supported !== 'boolean' || typeof value.limit !== 'string' || typeof value.min_cli !== 'string' || typeof value.min_sdk !== 'string')
|
|
209
|
+
return undefined;
|
|
210
|
+
return { field: typeof value.field === 'string' ? value.field : 'capabilities.directory.rosters', supported: value.supported, limit: value.limit, min_cli: value.min_cli, min_sdk: value.min_sdk };
|
|
211
|
+
}
|
|
@@ -1,10 +1,12 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.functionDirectoryManifestSchema = void 0;
|
|
4
|
+
const directory_roster_contract_1 = require("./directory-roster-contract");
|
|
4
5
|
const zod_1 = require("zod");
|
|
5
6
|
const directory_config_1 = require("./directory-config");
|
|
6
7
|
const directory_contract_1 = require("./directory-contract");
|
|
7
8
|
exports.functionDirectoryManifestSchema = zod_1.z.strictObject({
|
|
9
|
+
rosters: directory_roster_contract_1.functionDirectoryRostersSchema.optional(),
|
|
8
10
|
groups: directory_config_1.directoryScopesSchema.shape.groups.optional(),
|
|
9
11
|
resolve: directory_contract_1.functionDirectoryScopesSchema.shape.resolve.optional(),
|
|
10
|
-
}).refine((value) => value.groups !== undefined || value.resolve !== undefined, 'Declare directory groups, tenant resolution scopes, or both');
|
|
12
|
+
}).refine((value) => value.groups !== undefined || value.resolve !== undefined, 'Declare directory groups, tenant resolution scopes, or both').refine(value => value.rosters === undefined || value.resolve !== undefined, 'Service rosters also require directory resolve tenant scopes');
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
export declare const FUNCTION_DIRECTORY_ROSTER_PATH = "/api/managed-functions/directory/roster";
|
|
3
|
+
export declare const functionDirectoryRostersSchema: z.ZodArray<z.ZodString>;
|
|
4
|
+
export declare const directoryRosterQuerySchema: z.ZodObject<{
|
|
5
|
+
tenant: z.ZodString;
|
|
6
|
+
groupId: z.ZodString;
|
|
7
|
+
limit: z.ZodDefault<z.ZodNumber>;
|
|
8
|
+
cursor: z.ZodOptional<z.ZodString>;
|
|
9
|
+
}, z.core.$strict>;
|
|
10
|
+
export declare const directoryRosterPageSchema: z.ZodObject<{
|
|
11
|
+
members: z.ZodArray<z.ZodObject<{
|
|
12
|
+
id: z.ZodString;
|
|
13
|
+
sub: z.ZodString;
|
|
14
|
+
name: z.ZodString;
|
|
15
|
+
email: z.ZodString;
|
|
16
|
+
deactivated: z.ZodLiteral<false>;
|
|
17
|
+
}, z.core.$strict>>;
|
|
18
|
+
nextCursor: z.ZodNullable<z.ZodString>;
|
|
19
|
+
}, z.core.$strict>;
|
|
20
|
+
export type DirectoryRosterQuery = z.input<typeof directoryRosterQuerySchema>;
|
|
21
|
+
export type DirectoryRosterPage = z.infer<typeof directoryRosterPageSchema>;
|
|
22
|
+
export declare function readFunctionDirectoryRosterGroups(manifest: unknown): string[];
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.directoryRosterPageSchema = exports.directoryRosterQuerySchema = exports.functionDirectoryRostersSchema = exports.FUNCTION_DIRECTORY_ROSTER_PATH = void 0;
|
|
4
|
+
exports.readFunctionDirectoryRosterGroups = readFunctionDirectoryRosterGroups;
|
|
5
|
+
const zod_1 = require("zod");
|
|
6
|
+
const directory_config_1 = require("./directory-config");
|
|
7
|
+
const directory_contract_1 = require("./directory-contract");
|
|
8
|
+
exports.FUNCTION_DIRECTORY_ROSTER_PATH = '/api/managed-functions/directory/roster';
|
|
9
|
+
exports.functionDirectoryRostersSchema = zod_1.z.array(directory_config_1.directoryGroupIdSchema).min(1).max(16)
|
|
10
|
+
.refine(groups => new Set(groups).size === groups.length, 'Roster groups must be distinct');
|
|
11
|
+
exports.directoryRosterQuerySchema = zod_1.z.object({
|
|
12
|
+
tenant: directory_contract_1.directoryTenantSchema,
|
|
13
|
+
groupId: directory_config_1.directoryGroupIdSchema,
|
|
14
|
+
limit: zod_1.z.number().int().min(1).max(50).default(50),
|
|
15
|
+
cursor: zod_1.z.string().max(2048).optional(),
|
|
16
|
+
}).strict();
|
|
17
|
+
exports.directoryRosterPageSchema = zod_1.z.object({
|
|
18
|
+
members: zod_1.z.array(zod_1.z.object({ id: zod_1.z.string(), sub: zod_1.z.string(), name: zod_1.z.string(), email: zod_1.z.string(), deactivated: zod_1.z.literal(false) }).strict()).max(50),
|
|
19
|
+
nextCursor: zod_1.z.string().nullable(),
|
|
20
|
+
}).strict();
|
|
21
|
+
function readFunctionDirectoryRosterGroups(manifest) {
|
|
22
|
+
const parsed = zod_1.z.object({ capabilities: zod_1.z.object({ directory: zod_1.z.object({ rosters: exports.functionDirectoryRostersSchema.optional() }).optional() }).optional() }).safeParse(manifest);
|
|
23
|
+
return parsed.success ? parsed.data.capabilities?.directory?.rosters ?? [] : [];
|
|
24
|
+
}
|
package/dist/index.d.ts
CHANGED
|
@@ -36,7 +36,7 @@ export type { MonitoringDeltaEvent, MonitoringPublish, MonitoringDeliveryKey, Mo
|
|
|
36
36
|
export type { MonitoringCatalogQuery, MonitoringBucketCatalog } from './monitoring-contract';
|
|
37
37
|
export type { FunctionMonitoringAnnotation, MonitoringJson } from './monitoring-annotations';
|
|
38
38
|
export type { FunctionServiceMonitoringClient, FunctionServiceMonitoringOptions } from './monitoring';
|
|
39
|
-
export type { FunctionServiceProcessesClient, FunctionServiceProcessesOptions, FunctionProcessRunQuery, FunctionProcessRunSummary, FunctionProcessRunStatus, FunctionProcessRunsPage, FunctionProcessRunsPageQuery, FunctionProcessReadRequest, FunctionProcessCompletedAgentReferenceQuery, FunctionProcessCompletedAgentReference } from './processes';
|
|
39
|
+
export type { FunctionServiceProcessesClient, FunctionServiceProcessesOptions, FunctionProcessRunQuery, FunctionProcessRunSummary, FunctionProcessRunStatus, FunctionProcessRunsPage, FunctionProcessRunsPageQuery, FunctionProcessReadRequest, FunctionProcessCompletedAgentReferenceQuery, FunctionProcessCompletedAgentReference, FunctionProcessCompletedNode, FunctionProcessCompletedNodeQuery } from './processes';
|
|
40
40
|
export { installFunctionTracing, runWithFunctionTracing } from './tracing';
|
|
41
41
|
export { createFunctionStorageClient } from './storage';
|
|
42
42
|
import { type CacheManager } from "./cache";
|
|
@@ -52,3 +52,6 @@ export declare function createManagedFunctionContext({ env, }?: {
|
|
|
52
52
|
}): ManagedFunctionContext;
|
|
53
53
|
export * from './directory-contract';
|
|
54
54
|
export { createFunctionServiceDirectoryClient, type FunctionServiceDirectoryOptions, type FunctionServiceDirectoryClient } from './service-directory';
|
|
55
|
+
export * from './directory-roster-contract';
|
|
56
|
+
export { functionLatticeRunCreatorAccessSchema } from './lattice-provenance-contract';
|
|
57
|
+
export type { FunctionLatticeRunCreatorAccess } from './lattice-provenance-contract';
|
package/dist/index.js
CHANGED
|
@@ -14,7 +14,7 @@ var __exportStar = (this && this.__exportStar) || function(m, exports) {
|
|
|
14
14
|
for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
|
|
15
15
|
};
|
|
16
16
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
17
|
-
exports.createFunctionServiceDirectoryClient = exports.readCacheConfiguration = exports.cacheManifestSchema = exports.createCacheManager = exports.CacheError = exports.createFunctionStorageClient = exports.runWithFunctionTracing = exports.installFunctionTracing = exports.functionMonitoringAnnotationSchema = exports.monitoringPublishSchema = exports.monitoringEventsSchema = exports.monitoringPayloadHash = exports.FunctionMonitoringError = exports.createFunctionServiceMonitoringClient = exports.functionSourceJobAdmissionSchema = exports.functionAgentSourceExecutionSchema = exports.functionAgentConversationEvidenceRequestSchema = exports.functionAgentConversationEvidenceCaptureSchema = exports.functionAgentConversationEvidenceResponseSchema = exports.functionAgentSourceEvidenceCaptureSchema = exports.functionAgentSourceEvidenceRequestSchema = exports.functionAgentSourceResponseSchema = exports.createFunctionWorkflowEvidenceClient = exports.createFunctionServiceWorkflowsClient = exports.createFunctionAgentEvidenceClient = exports.FunctionAgentReadError = exports.createFunctionServiceAgentsClient = exports.FunctionProcessReadError = exports.createFunctionServiceProcessesClient = exports.functionLatticeHumanCompletionsPageSchema = exports.functionLatticeHumanCompletionsQuerySchema = exports.functionLatticeHumanCompletionSchema = exports.functionLatticeHumanCompletionQuerySchema = exports.functionLatticeExecutionContextSchema = exports.functionLatticeContextRequestSchema = exports.FunctionLatticeContextError = exports.FUNCTION_LATTICE_EXECUTION_TOKEN_HEADER = exports.FUNCTION_LATTICE_CONTEXT_PATH = exports.createFunctionInvocationClient = exports.functionLatticeStartProvenanceSchema = exports.functionLatticeParallelSnapshotQuerySchema = exports.functionLatticeParallelSnapshotSchema = exports.createFunctionLatticeClient = exports.readFunctionLatticeContextCapability = exports.functionLatticeContextCapabilitySchema = exports.FunctionDirectoryReadError = exports.createFunctionDirectoryClient = void 0;
|
|
17
|
+
exports.functionLatticeRunCreatorAccessSchema = exports.createFunctionServiceDirectoryClient = exports.readCacheConfiguration = exports.cacheManifestSchema = exports.createCacheManager = exports.CacheError = exports.createFunctionStorageClient = exports.runWithFunctionTracing = exports.installFunctionTracing = exports.functionMonitoringAnnotationSchema = exports.monitoringPublishSchema = exports.monitoringEventsSchema = exports.monitoringPayloadHash = exports.FunctionMonitoringError = exports.createFunctionServiceMonitoringClient = exports.functionSourceJobAdmissionSchema = exports.functionAgentSourceExecutionSchema = exports.functionAgentConversationEvidenceRequestSchema = exports.functionAgentConversationEvidenceCaptureSchema = exports.functionAgentConversationEvidenceResponseSchema = exports.functionAgentSourceEvidenceCaptureSchema = exports.functionAgentSourceEvidenceRequestSchema = exports.functionAgentSourceResponseSchema = exports.createFunctionWorkflowEvidenceClient = exports.createFunctionServiceWorkflowsClient = exports.createFunctionAgentEvidenceClient = exports.FunctionAgentReadError = exports.createFunctionServiceAgentsClient = exports.FunctionProcessReadError = exports.createFunctionServiceProcessesClient = exports.functionLatticeHumanCompletionsPageSchema = exports.functionLatticeHumanCompletionsQuerySchema = exports.functionLatticeHumanCompletionSchema = exports.functionLatticeHumanCompletionQuerySchema = exports.functionLatticeExecutionContextSchema = exports.functionLatticeContextRequestSchema = exports.FunctionLatticeContextError = exports.FUNCTION_LATTICE_EXECUTION_TOKEN_HEADER = exports.FUNCTION_LATTICE_CONTEXT_PATH = exports.createFunctionInvocationClient = exports.functionLatticeStartProvenanceSchema = exports.functionLatticeParallelSnapshotQuerySchema = exports.functionLatticeParallelSnapshotSchema = exports.createFunctionLatticeClient = exports.readFunctionLatticeContextCapability = exports.functionLatticeContextCapabilitySchema = exports.FunctionDirectoryReadError = exports.createFunctionDirectoryClient = void 0;
|
|
18
18
|
exports.createManagedFunctionContext = createManagedFunctionContext;
|
|
19
19
|
var directory_1 = require("./directory");
|
|
20
20
|
Object.defineProperty(exports, "createFunctionDirectoryClient", { enumerable: true, get: function () { return directory_1.createFunctionDirectoryClient; } });
|
|
@@ -139,3 +139,6 @@ function lazyValkeyStore(connection, local) {
|
|
|
139
139
|
__exportStar(require("./directory-contract"), exports);
|
|
140
140
|
var service_directory_1 = require("./service-directory");
|
|
141
141
|
Object.defineProperty(exports, "createFunctionServiceDirectoryClient", { enumerable: true, get: function () { return service_directory_1.createFunctionServiceDirectoryClient; } });
|
|
142
|
+
__exportStar(require("./directory-roster-contract"), exports);
|
|
143
|
+
var lattice_provenance_contract_5 = require("./lattice-provenance-contract");
|
|
144
|
+
Object.defineProperty(exports, "functionLatticeRunCreatorAccessSchema", { enumerable: true, get: function () { return lattice_provenance_contract_5.functionLatticeRunCreatorAccessSchema; } });
|
|
@@ -3,11 +3,14 @@ export declare const FUNCTION_INVOCATION_IDENTITY_TOKEN_HEADER = "x-sequence-inv
|
|
|
3
3
|
export declare const FUNCTION_INVOCATION_CONTEXT_PATH = "/api/managed-functions/invocation/context";
|
|
4
4
|
export declare const functionInvocationIdentityCapabilitySchema: z.ZodObject<{
|
|
5
5
|
identity: z.ZodLiteral<true>;
|
|
6
|
+
caller_capabilities: z.ZodOptional<z.ZodLiteral<true>>;
|
|
6
7
|
}, z.core.$strict>;
|
|
7
8
|
export declare function readFunctionInvocationIdentityCapability(manifest: unknown): boolean;
|
|
8
|
-
export declare const functionInvocationContextRequestSchema: z.ZodObject<{
|
|
9
|
+
export declare const functionInvocationContextRequestSchema: z.ZodDiscriminatedUnion<[z.ZodObject<{
|
|
9
10
|
operation: z.ZodLiteral<"getInvocationContext">;
|
|
10
|
-
}, z.core.$strict
|
|
11
|
+
}, z.core.$strict>, z.ZodObject<{
|
|
12
|
+
operation: z.ZodLiteral<"getCallerCapabilities">;
|
|
13
|
+
}, z.core.$strict>], "operation">;
|
|
11
14
|
export type FunctionInvocationContextRequest = z.infer<typeof functionInvocationContextRequestSchema>;
|
|
12
15
|
export declare const functionInvocationContextSchema: z.ZodObject<{
|
|
13
16
|
receiver: z.ZodObject<{
|
|
@@ -34,3 +37,23 @@ export declare class FunctionInvocationContextError extends Error {
|
|
|
34
37
|
readonly name = "FunctionInvocationContextError";
|
|
35
38
|
constructor(status: number, code: string, message: string);
|
|
36
39
|
}
|
|
40
|
+
export declare const functionInvocationCapabilitiesSchema: z.ZodObject<{
|
|
41
|
+
receiver: z.ZodObject<{
|
|
42
|
+
functionId: z.ZodString;
|
|
43
|
+
versionId: z.ZodString;
|
|
44
|
+
invocationId: z.ZodString;
|
|
45
|
+
orgId: z.ZodString;
|
|
46
|
+
serviceAccountId: z.ZodString;
|
|
47
|
+
serviceAccountSub: z.ZodString;
|
|
48
|
+
}, z.core.$strict>;
|
|
49
|
+
caller: z.ZodObject<{
|
|
50
|
+
kind: z.ZodEnum<{
|
|
51
|
+
human: "human";
|
|
52
|
+
service_account: "service_account";
|
|
53
|
+
system: "system";
|
|
54
|
+
}>;
|
|
55
|
+
sub: z.ZodString;
|
|
56
|
+
}, z.core.$strict>;
|
|
57
|
+
capabilities: z.ZodArray<z.ZodString>;
|
|
58
|
+
}, z.core.$strict>;
|
|
59
|
+
export type FunctionInvocationCapabilities = z.infer<typeof functionInvocationCapabilitiesSchema>;
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.FunctionInvocationContextError = exports.functionInvocationContextSchema = exports.functionInvocationContextRequestSchema = exports.functionInvocationIdentityCapabilitySchema = exports.FUNCTION_INVOCATION_CONTEXT_PATH = exports.FUNCTION_INVOCATION_IDENTITY_TOKEN_HEADER = void 0;
|
|
3
|
+
exports.functionInvocationCapabilitiesSchema = exports.FunctionInvocationContextError = exports.functionInvocationContextSchema = exports.functionInvocationContextRequestSchema = exports.functionInvocationIdentityCapabilitySchema = exports.FUNCTION_INVOCATION_CONTEXT_PATH = exports.FUNCTION_INVOCATION_IDENTITY_TOKEN_HEADER = void 0;
|
|
4
4
|
exports.readFunctionInvocationIdentityCapability = readFunctionInvocationIdentityCapability;
|
|
5
5
|
const zod_1 = require("zod");
|
|
6
6
|
exports.FUNCTION_INVOCATION_IDENTITY_TOKEN_HEADER = 'x-sequence-invocation-identity-token';
|
|
@@ -9,6 +9,7 @@ const identifier = zod_1.z.string().min(1).max(255);
|
|
|
9
9
|
const principal = zod_1.z.string().min(1).max(512);
|
|
10
10
|
exports.functionInvocationIdentityCapabilitySchema = zod_1.z.strictObject({
|
|
11
11
|
identity: zod_1.z.literal(true),
|
|
12
|
+
caller_capabilities: zod_1.z.literal(true).optional(),
|
|
12
13
|
});
|
|
13
14
|
function readFunctionInvocationIdentityCapability(manifest) {
|
|
14
15
|
if (typeof manifest !== 'object' || manifest === null)
|
|
@@ -18,18 +19,21 @@ function readFunctionInvocationIdentityCapability(manifest) {
|
|
|
18
19
|
return false;
|
|
19
20
|
return exports.functionInvocationIdentityCapabilitySchema.safeParse(Reflect.get(capabilities, 'invocation')).success;
|
|
20
21
|
}
|
|
21
|
-
exports.functionInvocationContextRequestSchema = zod_1.z.
|
|
22
|
-
operation: zod_1.z.literal('getInvocationContext'),
|
|
23
|
-
})
|
|
22
|
+
exports.functionInvocationContextRequestSchema = zod_1.z.discriminatedUnion('operation', [
|
|
23
|
+
zod_1.z.strictObject({ operation: zod_1.z.literal('getInvocationContext') }),
|
|
24
|
+
zod_1.z.strictObject({ operation: zod_1.z.literal('getCallerCapabilities') }),
|
|
25
|
+
]);
|
|
24
26
|
exports.functionInvocationContextSchema = zod_1.z.strictObject({
|
|
25
|
-
receiver: zod_1.z
|
|
27
|
+
receiver: zod_1.z
|
|
28
|
+
.strictObject({
|
|
26
29
|
functionId: identifier,
|
|
27
30
|
versionId: identifier,
|
|
28
31
|
invocationId: identifier,
|
|
29
32
|
orgId: identifier,
|
|
30
33
|
serviceAccountId: identifier,
|
|
31
34
|
serviceAccountSub: principal,
|
|
32
|
-
})
|
|
35
|
+
})
|
|
36
|
+
.refine((value) => value.serviceAccountSub === `service-account|${value.serviceAccountId}`, 'The receiver subject must identify the attached service account'),
|
|
33
37
|
caller: zod_1.z.strictObject({
|
|
34
38
|
kind: zod_1.z.enum(['human', 'service_account', 'system']),
|
|
35
39
|
sub: principal,
|
|
@@ -46,3 +50,14 @@ class FunctionInvocationContextError extends Error {
|
|
|
46
50
|
}
|
|
47
51
|
}
|
|
48
52
|
exports.FunctionInvocationContextError = FunctionInvocationContextError;
|
|
53
|
+
exports.functionInvocationCapabilitiesSchema = exports.functionInvocationContextSchema
|
|
54
|
+
.extend({
|
|
55
|
+
capabilities: zod_1.z
|
|
56
|
+
.array(zod_1.z
|
|
57
|
+
.string()
|
|
58
|
+
.min(1)
|
|
59
|
+
.max(140)
|
|
60
|
+
.regex(/^[a-z0-9][a-z0-9/_.:-]*$/))
|
|
61
|
+
.max(256),
|
|
62
|
+
})
|
|
63
|
+
.refine((value) => new Set(value.capabilities).size === value.capabilities.length, 'Capabilities must be unique');
|
package/dist/invocation.d.ts
CHANGED
|
@@ -1,8 +1,9 @@
|
|
|
1
|
-
import { type FunctionInvocationContext } from './invocation-contract';
|
|
1
|
+
import { type FunctionInvocationCapabilities, type FunctionInvocationContext } from './invocation-contract';
|
|
2
2
|
export * from './invocation-contract';
|
|
3
3
|
import type { FunctionInvocationClientOptions } from './invocation-client';
|
|
4
4
|
export type { FunctionInvocationClientOptions } from './invocation-client';
|
|
5
5
|
export interface FunctionInvocationClient {
|
|
6
6
|
getInvocationContext(): Promise<FunctionInvocationContext>;
|
|
7
|
+
getCallerCapabilities(): Promise<FunctionInvocationCapabilities>;
|
|
7
8
|
}
|
|
8
9
|
export declare function createFunctionInvocationClient({ request, baseUrl, fetchImpl, }: FunctionInvocationClientOptions): FunctionInvocationClient;
|
package/dist/invocation.js
CHANGED
|
@@ -34,7 +34,11 @@ const tokenClaimsSchema = zod_1.z.strictObject({
|
|
|
34
34
|
exp: zod_1.z.number().int().positive().max(Number.MAX_SAFE_INTEGER),
|
|
35
35
|
});
|
|
36
36
|
const errorSchema = zod_1.z.strictObject({
|
|
37
|
-
code: zod_1.z
|
|
37
|
+
code: zod_1.z
|
|
38
|
+
.string()
|
|
39
|
+
.min(1)
|
|
40
|
+
.max(128)
|
|
41
|
+
.regex(/^[a-z][a-z0-9_]*$/),
|
|
38
42
|
detail: zod_1.z.string().min(1).max(2000),
|
|
39
43
|
});
|
|
40
44
|
const invalidContext = () => new invocation_contract_1.FunctionInvocationContextError(401, 'invalid_context', 'This invocation has no valid identity credential');
|
|
@@ -75,10 +79,13 @@ function trustedOrigin(baseUrl) {
|
|
|
75
79
|
catch {
|
|
76
80
|
throw invalid();
|
|
77
81
|
}
|
|
78
|
-
const loopback = url.protocol === 'http:' &&
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
url.
|
|
82
|
+
const loopback = url.protocol === 'http:' && ['localhost', '127.0.0.1', '[::1]'].includes(url.hostname);
|
|
83
|
+
if ((!loopback && url.protocol !== 'https:') ||
|
|
84
|
+
url.username ||
|
|
85
|
+
url.password ||
|
|
86
|
+
url.pathname !== '/' ||
|
|
87
|
+
url.search ||
|
|
88
|
+
url.hash)
|
|
82
89
|
throw invalid();
|
|
83
90
|
return url.origin;
|
|
84
91
|
}
|
|
@@ -88,47 +95,50 @@ function requireFresh(claims) {
|
|
|
88
95
|
}
|
|
89
96
|
function matchesInvocation({ context, claims, }) {
|
|
90
97
|
const { receiver, caller } = context;
|
|
91
|
-
return receiver.functionId === claims.functionId &&
|
|
98
|
+
return (receiver.functionId === claims.functionId &&
|
|
92
99
|
receiver.versionId === claims.versionId &&
|
|
93
100
|
receiver.invocationId === claims.invocationId &&
|
|
94
101
|
receiver.orgId === claims.org &&
|
|
95
102
|
receiver.serviceAccountId === claims.serviceAccountId &&
|
|
96
|
-
caller.kind === claims.callerKind &&
|
|
103
|
+
caller.kind === claims.callerKind &&
|
|
104
|
+
caller.sub === claims.callerSub);
|
|
97
105
|
}
|
|
98
106
|
function createFunctionInvocationClient({ request, baseUrl, fetchImpl = globalThis.fetch, }) {
|
|
99
107
|
const url = `${trustedOrigin(baseUrl)}${invocation_contract_1.FUNCTION_INVOCATION_CONTEXT_PATH}`;
|
|
100
108
|
const { token, claims } = readCredential({ request });
|
|
109
|
+
async function read(operation, schema) {
|
|
110
|
+
requireFresh(claims);
|
|
111
|
+
let response;
|
|
112
|
+
try {
|
|
113
|
+
response = await fetchImpl(url, {
|
|
114
|
+
method: 'POST',
|
|
115
|
+
headers: {
|
|
116
|
+
'content-type': 'application/json',
|
|
117
|
+
[invocation_contract_1.FUNCTION_INVOCATION_IDENTITY_TOKEN_HEADER]: token,
|
|
118
|
+
},
|
|
119
|
+
body: JSON.stringify(invocation_contract_1.functionInvocationContextRequestSchema.parse({ operation })),
|
|
120
|
+
redirect: 'error',
|
|
121
|
+
signal: AbortSignal.timeout(30_000),
|
|
122
|
+
});
|
|
123
|
+
}
|
|
124
|
+
catch {
|
|
125
|
+
throw new invocation_contract_1.FunctionInvocationContextError(502, 'context_request_failed', 'The invocation context request failed');
|
|
126
|
+
}
|
|
127
|
+
if (response.redirected || (response.status >= 300 && response.status < 400))
|
|
128
|
+
throw new invocation_contract_1.FunctionInvocationContextError(502, 'redirect_refused', 'The invocation context request must not redirect');
|
|
129
|
+
const result = await response.json().catch(() => null);
|
|
130
|
+
if (!response.ok) {
|
|
131
|
+
const error = errorSchema.safeParse(result);
|
|
132
|
+
throw new invocation_contract_1.FunctionInvocationContextError(response.status, error.success ? error.data.code : 'context_read_failed', error.success && !error.data.detail.includes(token) ? error.data.detail : 'Invocation context read failed');
|
|
133
|
+
}
|
|
134
|
+
requireFresh(claims);
|
|
135
|
+
const parsed = schema.safeParse(result);
|
|
136
|
+
if (!parsed.success || !matchesInvocation({ context: parsed.data, claims }))
|
|
137
|
+
throw new invocation_contract_1.FunctionInvocationContextError(502, 'malformed_response', 'Atlas returned an invalid invocation context response');
|
|
138
|
+
return parsed.data;
|
|
139
|
+
}
|
|
101
140
|
return {
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
let response;
|
|
105
|
-
try {
|
|
106
|
-
response = await fetchImpl(url, {
|
|
107
|
-
method: 'POST',
|
|
108
|
-
headers: {
|
|
109
|
-
'content-type': 'application/json',
|
|
110
|
-
[invocation_contract_1.FUNCTION_INVOCATION_IDENTITY_TOKEN_HEADER]: token,
|
|
111
|
-
},
|
|
112
|
-
body: JSON.stringify(invocation_contract_1.functionInvocationContextRequestSchema.parse({ operation: 'getInvocationContext' })),
|
|
113
|
-
redirect: 'error', signal: AbortSignal.timeout(30_000),
|
|
114
|
-
});
|
|
115
|
-
}
|
|
116
|
-
catch {
|
|
117
|
-
throw new invocation_contract_1.FunctionInvocationContextError(502, 'context_request_failed', 'The invocation context request failed');
|
|
118
|
-
}
|
|
119
|
-
if (response.redirected || (response.status >= 300 && response.status < 400))
|
|
120
|
-
throw new invocation_contract_1.FunctionInvocationContextError(502, 'redirect_refused', 'The invocation context request must not redirect');
|
|
121
|
-
const result = await response.json().catch(() => null);
|
|
122
|
-
if (!response.ok) {
|
|
123
|
-
const error = errorSchema.safeParse(result);
|
|
124
|
-
throw new invocation_contract_1.FunctionInvocationContextError(response.status, error.success ? error.data.code : 'context_read_failed', error.success && !error.data.detail.includes(token)
|
|
125
|
-
? error.data.detail : 'Invocation context read failed');
|
|
126
|
-
}
|
|
127
|
-
requireFresh(claims);
|
|
128
|
-
const parsed = invocation_contract_1.functionInvocationContextSchema.safeParse(result);
|
|
129
|
-
if (!parsed.success || !matchesInvocation({ context: parsed.data, claims }))
|
|
130
|
-
throw new invocation_contract_1.FunctionInvocationContextError(502, 'malformed_response', 'Atlas returned an invalid invocation context response');
|
|
131
|
-
return parsed.data;
|
|
132
|
-
},
|
|
141
|
+
getInvocationContext: () => read('getInvocationContext', invocation_contract_1.functionInvocationContextSchema),
|
|
142
|
+
getCallerCapabilities: () => read('getCallerCapabilities', invocation_contract_1.functionInvocationCapabilitiesSchema),
|
|
133
143
|
};
|
|
134
144
|
}
|