@stigmer/sdk 3.35.0 → 3.37.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/activity.d.ts.map +1 -1
- package/activity.js.map +1 -1
- package/artifact-routing.d.ts.map +1 -1
- package/artifact-routing.js.map +1 -1
- package/authorization-config.d.ts.map +1 -1
- package/authorization-config.js.map +1 -1
- package/billing.d.ts.map +1 -1
- package/billing.js.map +1 -1
- package/config.d.ts.map +1 -1
- package/config.js.map +1 -1
- package/cursor-accounts.d.ts.map +1 -1
- package/cursor-accounts.js.map +1 -1
- package/ensure-identity-account.d.ts.map +1 -1
- package/ensure-identity-account.js.map +1 -1
- package/errors.d.ts.map +1 -1
- package/errors.js.map +1 -1
- package/execution/approval-provenance.d.ts.map +1 -1
- package/execution/approval-provenance.js.map +1 -1
- package/execution/conversation-rules.d.ts.map +1 -1
- package/execution/conversation-rules.js.map +1 -1
- package/execution/execution-phases.d.ts.map +1 -1
- package/execution/execution-phases.js.map +1 -1
- package/execution/file-review-fold.d.ts.map +1 -1
- package/execution/file-review-fold.js.map +1 -1
- package/execution/to-display-file-change.d.ts.map +1 -1
- package/execution/to-display-file-change.js.map +1 -1
- package/execution/tool-view.d.ts.map +1 -1
- package/execution/tool-view.js.map +1 -1
- package/execution/transcript.d.ts.map +1 -1
- package/execution/transcript.js.map +1 -1
- package/gen/agent.d.ts.map +1 -1
- package/gen/agent.js.map +1 -1
- package/gen/agentchannel.d.ts.map +1 -1
- package/gen/agentchannel.js.map +1 -1
- package/gen/agentexecution.d.ts.map +1 -1
- package/gen/agentexecution.js.map +1 -1
- package/gen/agentinstance.d.ts.map +1 -1
- package/gen/agentinstance.js.map +1 -1
- package/gen/agentshare.d.ts.map +1 -1
- package/gen/agentshare.js.map +1 -1
- package/gen/apikey.d.ts.map +1 -1
- package/gen/apikey.js.map +1 -1
- package/gen/artifact.d.ts.map +1 -1
- package/gen/artifact.js.map +1 -1
- package/gen/authorization-config.d.ts.map +1 -1
- package/gen/authorization-config.js +2 -2
- package/gen/authorization-config.js.map +1 -1
- package/gen/bidi-stream.d.ts.map +1 -1
- package/gen/bidi-stream.js.map +1 -1
- package/gen/channelapp.d.ts.map +1 -1
- package/gen/channelapp.js.map +1 -1
- package/gen/client.d.ts.map +1 -1
- package/gen/client.js.map +1 -1
- package/gen/environment.d.ts.map +1 -1
- package/gen/environment.js.map +1 -1
- package/gen/errors.d.ts.map +1 -1
- package/gen/errors.js.map +1 -1
- package/gen/executioncontext.d.ts.map +1 -1
- package/gen/executioncontext.js.map +1 -1
- package/gen/iampolicy.d.ts.map +1 -1
- package/gen/iampolicy.js.map +1 -1
- package/gen/identityaccount.d.ts.map +1 -1
- package/gen/identityaccount.js.map +1 -1
- package/gen/identityprovider.d.ts.map +1 -1
- package/gen/identityprovider.js.map +1 -1
- package/gen/invitation.d.ts.map +1 -1
- package/gen/invitation.js.map +1 -1
- package/gen/license.d.ts.map +1 -1
- package/gen/license.js.map +1 -1
- package/gen/mcpserver.d.ts.map +1 -1
- package/gen/mcpserver.js.map +1 -1
- package/gen/memory.d.ts.map +1 -1
- package/gen/memory.js.map +1 -1
- package/gen/oauthapp.d.ts.map +1 -1
- package/gen/oauthapp.js.map +1 -1
- package/gen/organization.d.ts.map +1 -1
- package/gen/organization.js.map +1 -1
- package/gen/plan.d.ts.map +1 -1
- package/gen/plan.js.map +1 -1
- package/gen/platformclient.d.ts.map +1 -1
- package/gen/platformclient.js.map +1 -1
- package/gen/plugin.d.ts.map +1 -1
- package/gen/plugin.js.map +1 -1
- package/gen/proto-utils.d.ts.map +1 -1
- package/gen/proto-utils.js.map +1 -1
- package/gen/resource-availability.d.ts.map +1 -1
- package/gen/resource-availability.js.map +1 -1
- package/gen/schedule.d.ts.map +1 -1
- package/gen/schedule.js.map +1 -1
- package/gen/session.d.ts.map +1 -1
- package/gen/session.js.map +1 -1
- package/gen/skill.d.ts.map +1 -1
- package/gen/skill.js.map +1 -1
- package/gen/subscription.d.ts.map +1 -1
- package/gen/subscription.js.map +1 -1
- package/gen/team.d.ts.map +1 -1
- package/gen/team.js.map +1 -1
- package/gen/types.d.ts.map +1 -1
- package/gen/types.js.map +1 -1
- package/gen/workflow.d.ts.map +1 -1
- package/gen/workflow.js.map +1 -1
- package/gen/workflowexecution.d.ts.map +1 -1
- package/gen/workflowexecution.js.map +1 -1
- package/gen/workflowinstance.d.ts.map +1 -1
- package/gen/workflowinstance.js.map +1 -1
- package/github.d.ts.map +1 -1
- package/github.js.map +1 -1
- package/guest-auth.d.ts.map +1 -1
- package/guest-auth.js.map +1 -1
- package/iam-principal.d.ts +6 -0
- package/iam-principal.d.ts.map +1 -1
- package/iam-principal.js +19 -0
- package/iam-principal.js.map +1 -1
- package/iam-role.d.ts.map +1 -1
- package/iam-role.js.map +1 -1
- package/index.d.ts +1 -1
- package/index.d.ts.map +1 -1
- package/index.js +1 -1
- package/index.js.map +1 -1
- package/internal/interceptors.d.ts.map +1 -1
- package/internal/interceptors.js.map +1 -1
- package/manifest/client.d.ts.map +1 -1
- package/manifest/client.js.map +1 -1
- package/manifest/document.d.ts.map +1 -1
- package/manifest/document.js.map +1 -1
- package/manifest/index.d.ts.map +1 -1
- package/manifest/index.js.map +1 -1
- package/manifest/parse.d.ts.map +1 -1
- package/manifest/parse.js.map +1 -1
- package/manifest/redaction.d.ts.map +1 -1
- package/manifest/redaction.js.map +1 -1
- package/manifest/registry.d.ts.map +1 -1
- package/manifest/registry.js.map +1 -1
- package/manifest/serialize.d.ts.map +1 -1
- package/manifest/serialize.js.map +1 -1
- package/mcpserver-connect.d.ts.map +1 -1
- package/mcpserver-connect.js.map +1 -1
- package/node.d.ts.map +1 -1
- package/node.js.map +1 -1
- package/package.json +2 -2
- package/platform-client-auth.d.ts.map +1 -1
- package/platform-client-auth.js.map +1 -1
- package/platform.d.ts.map +1 -1
- package/platform.js.map +1 -1
- package/plugin.d.ts.map +1 -1
- package/plugin.js.map +1 -1
- package/provider-standing.d.ts.map +1 -1
- package/provider-standing.js.map +1 -1
- package/resource-availability.d.ts.map +1 -1
- package/resource-availability.js.map +1 -1
- package/runner-adapter.d.ts.map +1 -1
- package/runner-adapter.js.map +1 -1
- package/search.d.ts.map +1 -1
- package/search.js.map +1 -1
- package/session.d.ts.map +1 -1
- package/session.js.map +1 -1
- package/sharing.d.ts.map +1 -1
- package/sharing.js.map +1 -1
- package/skill.d.ts.map +1 -1
- package/skill.js.map +1 -1
- package/src/gen/authorization-config.ts +2 -2
- package/src/iam-principal.ts +24 -0
- package/src/index.ts +1 -0
- package/stigmer.d.ts.map +1 -1
- package/stigmer.js.map +1 -1
- package/transport.d.ts.map +1 -1
- package/transport.js.map +1 -1
- package/__tests__/billing.test.d.ts +0 -2
- package/__tests__/billing.test.d.ts.map +0 -1
- package/__tests__/billing.test.js +0 -120
- package/__tests__/billing.test.js.map +0 -1
- package/__tests__/config.test.d.ts +0 -2
- package/__tests__/config.test.d.ts.map +0 -1
- package/__tests__/config.test.js +0 -35
- package/__tests__/config.test.js.map +0 -1
- package/__tests__/ensure-identity-account.test.d.ts +0 -2
- package/__tests__/ensure-identity-account.test.d.ts.map +0 -1
- package/__tests__/ensure-identity-account.test.js +0 -108
- package/__tests__/ensure-identity-account.test.js.map +0 -1
- package/__tests__/errors.test.d.ts +0 -2
- package/__tests__/errors.test.d.ts.map +0 -1
- package/__tests__/errors.test.js +0 -228
- package/__tests__/errors.test.js.map +0 -1
- package/__tests__/gen/errors.test.d.ts +0 -2
- package/__tests__/gen/errors.test.d.ts.map +0 -1
- package/__tests__/gen/errors.test.js +0 -97
- package/__tests__/gen/errors.test.js.map +0 -1
- package/__tests__/gen/invitation-client.test.d.ts +0 -2
- package/__tests__/gen/invitation-client.test.d.ts.map +0 -1
- package/__tests__/gen/invitation-client.test.js +0 -106
- package/__tests__/gen/invitation-client.test.js.map +0 -1
- package/__tests__/gen/proto-utils.test.d.ts +0 -2
- package/__tests__/gen/proto-utils.test.d.ts.map +0 -1
- package/__tests__/gen/proto-utils.test.js +0 -85
- package/__tests__/gen/proto-utils.test.js.map +0 -1
- package/__tests__/gen/session-client.test.d.ts +0 -2
- package/__tests__/gen/session-client.test.d.ts.map +0 -1
- package/__tests__/gen/session-client.test.js +0 -152
- package/__tests__/gen/session-client.test.js.map +0 -1
- package/__tests__/guest-auth.test.d.ts +0 -2
- package/__tests__/guest-auth.test.d.ts.map +0 -1
- package/__tests__/guest-auth.test.js +0 -223
- package/__tests__/guest-auth.test.js.map +0 -1
- package/__tests__/iam-principal.test.d.ts +0 -2
- package/__tests__/iam-principal.test.d.ts.map +0 -1
- package/__tests__/iam-principal.test.js +0 -65
- package/__tests__/iam-principal.test.js.map +0 -1
- package/__tests__/manifest.test.d.ts +0 -2
- package/__tests__/manifest.test.d.ts.map +0 -1
- package/__tests__/manifest.test.js +0 -306
- package/__tests__/manifest.test.js.map +0 -1
- package/__tests__/mcpserver-connect.test.d.ts +0 -2
- package/__tests__/mcpserver-connect.test.d.ts.map +0 -1
- package/__tests__/mcpserver-connect.test.js +0 -146
- package/__tests__/mcpserver-connect.test.js.map +0 -1
- package/__tests__/node.test.d.ts +0 -2
- package/__tests__/node.test.d.ts.map +0 -1
- package/__tests__/node.test.js +0 -67
- package/__tests__/node.test.js.map +0 -1
- package/__tests__/platform-client-auth.test.d.ts +0 -2
- package/__tests__/platform-client-auth.test.d.ts.map +0 -1
- package/__tests__/platform-client-auth.test.js +0 -59
- package/__tests__/platform-client-auth.test.js.map +0 -1
- package/__tests__/platform.test.d.ts +0 -2
- package/__tests__/platform.test.d.ts.map +0 -1
- package/__tests__/platform.test.js +0 -52
- package/__tests__/platform.test.js.map +0 -1
- package/__tests__/plugin.test.d.ts +0 -2
- package/__tests__/plugin.test.d.ts.map +0 -1
- package/__tests__/plugin.test.js +0 -74
- package/__tests__/plugin.test.js.map +0 -1
- package/__tests__/resource-availability.test.d.ts +0 -2
- package/__tests__/resource-availability.test.d.ts.map +0 -1
- package/__tests__/resource-availability.test.js +0 -80
- package/__tests__/resource-availability.test.js.map +0 -1
- package/__tests__/runner-adapter.test.d.ts +0 -2
- package/__tests__/runner-adapter.test.d.ts.map +0 -1
- package/__tests__/runner-adapter.test.js +0 -88
- package/__tests__/runner-adapter.test.js.map +0 -1
- package/__tests__/session.test.d.ts +0 -6
- package/__tests__/session.test.d.ts.map +0 -1
- package/__tests__/session.test.js +0 -50
- package/__tests__/session.test.js.map +0 -1
- package/__tests__/sharing.test.d.ts +0 -2
- package/__tests__/sharing.test.d.ts.map +0 -1
- package/__tests__/sharing.test.js +0 -106
- package/__tests__/sharing.test.js.map +0 -1
- package/__tests__/skill.test.d.ts +0 -2
- package/__tests__/skill.test.d.ts.map +0 -1
- package/__tests__/skill.test.js +0 -117
- package/__tests__/skill.test.js.map +0 -1
- package/__tests__/stigmer.test.d.ts +0 -2
- package/__tests__/stigmer.test.d.ts.map +0 -1
- package/__tests__/stigmer.test.js +0 -127
- package/__tests__/stigmer.test.js.map +0 -1
- package/__tests__/update-input-roundtrip.test.d.ts +0 -2
- package/__tests__/update-input-roundtrip.test.d.ts.map +0 -1
- package/__tests__/update-input-roundtrip.test.js +0 -775
- package/__tests__/update-input-roundtrip.test.js.map +0 -1
- package/__tests__/update-input.test.d.ts +0 -2
- package/__tests__/update-input.test.d.ts.map +0 -1
- package/__tests__/update-input.test.js +0 -188
- package/__tests__/update-input.test.js.map +0 -1
- package/execution/__tests__/approval-provenance.test.d.ts +0 -2
- package/execution/__tests__/approval-provenance.test.d.ts.map +0 -1
- package/execution/__tests__/approval-provenance.test.js +0 -42
- package/execution/__tests__/approval-provenance.test.js.map +0 -1
- package/execution/__tests__/file-review-fold.corpus.test.d.ts +0 -2
- package/execution/__tests__/file-review-fold.corpus.test.d.ts.map +0 -1
- package/execution/__tests__/file-review-fold.corpus.test.js +0 -82
- package/execution/__tests__/file-review-fold.corpus.test.js.map +0 -1
- package/execution/__tests__/file-review-fold.test.d.ts +0 -2
- package/execution/__tests__/file-review-fold.test.d.ts.map +0 -1
- package/execution/__tests__/file-review-fold.test.js +0 -184
- package/execution/__tests__/file-review-fold.test.js.map +0 -1
- package/execution/__tests__/to-display-file-change.test.d.ts +0 -2
- package/execution/__tests__/to-display-file-change.test.d.ts.map +0 -1
- package/execution/__tests__/to-display-file-change.test.js +0 -81
- package/execution/__tests__/to-display-file-change.test.js.map +0 -1
- package/execution/__tests__/tool-view.file-changes.test.d.ts +0 -2
- package/execution/__tests__/tool-view.file-changes.test.d.ts.map +0 -1
- package/execution/__tests__/tool-view.file-changes.test.js +0 -86
- package/execution/__tests__/tool-view.file-changes.test.js.map +0 -1
- package/execution/__tests__/tool-view.fixtures.test.d.ts +0 -2
- package/execution/__tests__/tool-view.fixtures.test.d.ts.map +0 -1
- package/execution/__tests__/tool-view.fixtures.test.js +0 -152
- package/execution/__tests__/tool-view.fixtures.test.js.map +0 -1
- package/execution/__tests__/tool-view.output-ref.test.d.ts +0 -2
- package/execution/__tests__/tool-view.output-ref.test.d.ts.map +0 -1
- package/execution/__tests__/tool-view.output-ref.test.js +0 -64
- package/execution/__tests__/tool-view.output-ref.test.js.map +0 -1
- package/execution/__tests__/tool-view.read.test.d.ts +0 -2
- package/execution/__tests__/tool-view.read.test.d.ts.map +0 -1
- package/execution/__tests__/tool-view.read.test.js +0 -56
- package/execution/__tests__/tool-view.read.test.js.map +0 -1
- package/execution/__tests__/tool-view.search.test.d.ts +0 -2
- package/execution/__tests__/tool-view.search.test.d.ts.map +0 -1
- package/execution/__tests__/tool-view.search.test.js +0 -200
- package/execution/__tests__/tool-view.search.test.js.map +0 -1
- package/execution/__tests__/tool-view.shell.test.d.ts +0 -2
- package/execution/__tests__/tool-view.shell.test.d.ts.map +0 -1
- package/execution/__tests__/tool-view.shell.test.js +0 -104
- package/execution/__tests__/tool-view.shell.test.js.map +0 -1
- package/execution/__tests__/transcript.test.d.ts +0 -2
- package/execution/__tests__/transcript.test.d.ts.map +0 -1
- package/execution/__tests__/transcript.test.js +0 -591
- package/execution/__tests__/transcript.test.js.map +0 -1
- package/node.test.d.ts +0 -2
- package/node.test.d.ts.map +0 -1
- package/node.test.js +0 -35
- package/node.test.js.map +0 -1
- package/src/__tests__/billing.test.ts +0 -146
- package/src/__tests__/config.test.ts +0 -52
- package/src/__tests__/ensure-identity-account.test.ts +0 -146
- package/src/__tests__/errors.test.ts +0 -349
- package/src/__tests__/gen/errors.test.ts +0 -138
- package/src/__tests__/gen/invitation-client.test.ts +0 -132
- package/src/__tests__/gen/proto-utils.test.ts +0 -99
- package/src/__tests__/gen/session-client.test.ts +0 -208
- package/src/__tests__/guest-auth.test.ts +0 -287
- package/src/__tests__/iam-principal.test.ts +0 -82
- package/src/__tests__/manifest.test.ts +0 -362
- package/src/__tests__/mcpserver-connect.test.ts +0 -181
- package/src/__tests__/node.test.ts +0 -74
- package/src/__tests__/platform-client-auth.test.ts +0 -76
- package/src/__tests__/platform.test.ts +0 -74
- package/src/__tests__/plugin.test.ts +0 -92
- package/src/__tests__/resource-availability.test.ts +0 -118
- package/src/__tests__/runner-adapter.test.ts +0 -122
- package/src/__tests__/session.test.ts +0 -66
- package/src/__tests__/sharing.test.ts +0 -159
- package/src/__tests__/skill.test.ts +0 -150
- package/src/__tests__/stigmer.test.ts +0 -170
- package/src/__tests__/update-input-roundtrip.test.ts +0 -1007
- package/src/__tests__/update-input.test.ts +0 -250
- package/src/execution/__tests__/approval-provenance.test.ts +0 -60
- package/src/execution/__tests__/file-review-fold.corpus.test.ts +0 -127
- package/src/execution/__tests__/file-review-fold.test.ts +0 -281
- package/src/execution/__tests__/to-display-file-change.test.ts +0 -106
- package/src/execution/__tests__/tool-view.file-changes.test.ts +0 -100
- package/src/execution/__tests__/tool-view.fixtures.test.ts +0 -225
- package/src/execution/__tests__/tool-view.output-ref.test.ts +0 -76
- package/src/execution/__tests__/tool-view.read.test.ts +0 -71
- package/src/execution/__tests__/tool-view.search.test.ts +0 -264
- package/src/execution/__tests__/tool-view.shell.test.ts +0 -127
- package/src/execution/__tests__/transcript.golden.md +0 -100
- package/src/execution/__tests__/transcript.test.ts +0 -697
- package/src/node.test.ts +0 -38
|
@@ -1,74 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Pins PlatformClient.getServerInfo's edition-to-mode mapping: the client
|
|
3
|
-
* reports the server's edition through the one converter
|
|
4
|
-
* (`deploymentModeOf`), so a third edition on the wire reaches consumers
|
|
5
|
-
* as its own mode and never collapses into "cloud" by accident. The raw
|
|
6
|
-
* edition rides beside it for callers that want the wire value.
|
|
7
|
-
*
|
|
8
|
-
* Also pins the authentication posture across the wire: a server's `true`
|
|
9
|
-
* and `false` reach callers as they were sent, and a server that predates
|
|
10
|
-
* the field answers `undefined`, never `false` — the difference between
|
|
11
|
-
* "this server trusts every request" and "this server did not say", which
|
|
12
|
-
* a console meeting an older server must not confuse.
|
|
13
|
-
*/
|
|
14
|
-
import { describe, expect, it } from "vitest";
|
|
15
|
-
import { createRouterTransport } from "@connectrpc/connect";
|
|
16
|
-
import { create } from "@bufbuild/protobuf";
|
|
17
|
-
import {
|
|
18
|
-
GetServerInfoOutputSchema,
|
|
19
|
-
PlatformQueryController,
|
|
20
|
-
ServerEdition,
|
|
21
|
-
} from "@stigmer/protos/ai/stigmer/platform/v1/server_info_pb";
|
|
22
|
-
|
|
23
|
-
import { PlatformClient } from "../platform";
|
|
24
|
-
|
|
25
|
-
function clientAnswering(
|
|
26
|
-
edition: ServerEdition,
|
|
27
|
-
authenticationRequired?: boolean,
|
|
28
|
-
): PlatformClient {
|
|
29
|
-
return new PlatformClient(
|
|
30
|
-
createRouterTransport(({ service }) => {
|
|
31
|
-
service(PlatformQueryController, {
|
|
32
|
-
getServerInfo: () =>
|
|
33
|
-
create(GetServerInfoOutputSchema, {
|
|
34
|
-
edition,
|
|
35
|
-
version: "1.2.3",
|
|
36
|
-
...(authenticationRequired !== undefined
|
|
37
|
-
? { authenticationRequired }
|
|
38
|
-
: {}),
|
|
39
|
-
}),
|
|
40
|
-
});
|
|
41
|
-
}),
|
|
42
|
-
);
|
|
43
|
-
}
|
|
44
|
-
|
|
45
|
-
describe("PlatformClient.getServerInfo", () => {
|
|
46
|
-
it.each([
|
|
47
|
-
[ServerEdition.oss, "local"],
|
|
48
|
-
[ServerEdition.enterprise, "enterprise"],
|
|
49
|
-
[ServerEdition.cloud, "cloud"],
|
|
50
|
-
] as const)(
|
|
51
|
-
"maps edition %d to deploymentMode %s and keeps the raw edition",
|
|
52
|
-
async (edition, mode) => {
|
|
53
|
-
const info = await clientAnswering(edition).getServerInfo();
|
|
54
|
-
expect(info.deploymentMode).toBe(mode);
|
|
55
|
-
expect(info.edition).toBe(edition);
|
|
56
|
-
expect(info.version).toBe("1.2.3");
|
|
57
|
-
},
|
|
58
|
-
);
|
|
59
|
-
|
|
60
|
-
it.each([
|
|
61
|
-
[true, true],
|
|
62
|
-
[false, false],
|
|
63
|
-
[undefined, undefined],
|
|
64
|
-
] as const)(
|
|
65
|
-
"reports a server's authentication posture of %s as %s",
|
|
66
|
-
async (sent, reported) => {
|
|
67
|
-
const info = await clientAnswering(
|
|
68
|
-
ServerEdition.cloud,
|
|
69
|
-
sent,
|
|
70
|
-
).getServerInfo();
|
|
71
|
-
expect(info.authenticationRequired).toBe(reported);
|
|
72
|
-
},
|
|
73
|
-
);
|
|
74
|
-
});
|
|
@@ -1,92 +0,0 @@
|
|
|
1
|
-
// Wire-shape tests for RoutedPluginClient's size-routed push: the plugin
|
|
2
|
-
// binding of the shared artifact routing. The routing mechanism itself is
|
|
3
|
-
// pinned by skill.test.ts; these arms pin that the plugin binding reads
|
|
4
|
-
// and rewrites ITS request shape (org, artifact, artifactUploadRef,
|
|
5
|
-
// visibility, message) and mints through ITS createArtifactUploadUrl.
|
|
6
|
-
import { describe, expect, it, vi } from "vitest";
|
|
7
|
-
import { createRouterTransport, type Transport } from "@connectrpc/connect";
|
|
8
|
-
import { create } from "@bufbuild/protobuf";
|
|
9
|
-
import { PluginCommandController } from "@stigmer/protos/ai/stigmer/agentic/plugin/v1/command_pb";
|
|
10
|
-
import { PluginSchema } from "@stigmer/protos/ai/stigmer/agentic/plugin/v1/api_pb";
|
|
11
|
-
import {
|
|
12
|
-
PluginArtifactUploadUrlSchema,
|
|
13
|
-
PushPluginRequestSchema,
|
|
14
|
-
type PushPluginRequest,
|
|
15
|
-
} from "@stigmer/protos/ai/stigmer/agentic/plugin/v1/io_pb";
|
|
16
|
-
import { ApiResourceVisibility } from "@stigmer/protos/ai/stigmer/commons/apiresource/enum_pb";
|
|
17
|
-
import { RoutedPluginClient } from "../plugin.js";
|
|
18
|
-
import { MAX_INLINE_ARTIFACT_BYTES } from "../skill.js";
|
|
19
|
-
|
|
20
|
-
const STAGING_URL = "http://stage.example/v1/skill-artifacts/uploads/sau_p";
|
|
21
|
-
|
|
22
|
-
interface Captured {
|
|
23
|
-
pushes: PushPluginRequest[];
|
|
24
|
-
mints: number;
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
function fakeTransport(captured: Captured): Transport {
|
|
28
|
-
return createRouterTransport(({ service }) => {
|
|
29
|
-
service(PluginCommandController, {
|
|
30
|
-
push: (req) => {
|
|
31
|
-
captured.pushes.push(req);
|
|
32
|
-
return create(PluginSchema, {});
|
|
33
|
-
},
|
|
34
|
-
createArtifactUploadUrl: (req) => {
|
|
35
|
-
captured.mints++;
|
|
36
|
-
expect(req.org).toBe("acme");
|
|
37
|
-
expect(req.sizeBytes).toBeGreaterThan(0n);
|
|
38
|
-
return create(PluginArtifactUploadUrlSchema, {
|
|
39
|
-
url: STAGING_URL,
|
|
40
|
-
artifactUploadRef: "sau_p",
|
|
41
|
-
ttlSeconds: 900,
|
|
42
|
-
});
|
|
43
|
-
},
|
|
44
|
-
});
|
|
45
|
-
});
|
|
46
|
-
}
|
|
47
|
-
|
|
48
|
-
describe("RoutedPluginClient.push size routing", () => {
|
|
49
|
-
it("keeps a small archive inline", async () => {
|
|
50
|
-
const captured: Captured = { pushes: [], mints: 0 };
|
|
51
|
-
const client = new RoutedPluginClient(fakeTransport(captured));
|
|
52
|
-
await client.push(
|
|
53
|
-
create(PushPluginRequestSchema, {
|
|
54
|
-
org: "acme",
|
|
55
|
-
artifact: new Uint8Array(2048),
|
|
56
|
-
}),
|
|
57
|
-
);
|
|
58
|
-
expect(captured.mints).toBe(0);
|
|
59
|
-
expect(captured.pushes[0]?.artifact.length).toBe(2048);
|
|
60
|
-
});
|
|
61
|
-
|
|
62
|
-
it("stages a large archive through the plugin's own mint and pushes by reference, keeping the envelope", async () => {
|
|
63
|
-
const captured: Captured = { pushes: [], mints: 0 };
|
|
64
|
-
const record: { url?: string; bytes?: number } = {};
|
|
65
|
-
const fetchImpl = vi.fn(async (url: unknown, init: RequestInit) => {
|
|
66
|
-
record.url = String(url);
|
|
67
|
-
record.bytes =
|
|
68
|
-
init.body instanceof Uint8Array ? init.body.byteLength : -1;
|
|
69
|
-
return new Response(null, { status: 200 });
|
|
70
|
-
}) as unknown as typeof globalThis.fetch;
|
|
71
|
-
const client = new RoutedPluginClient(fakeTransport(captured), fetchImpl);
|
|
72
|
-
const artifact = new Uint8Array(MAX_INLINE_ARTIFACT_BYTES + 1);
|
|
73
|
-
|
|
74
|
-
await client.push(
|
|
75
|
-
create(PushPluginRequestSchema, {
|
|
76
|
-
org: "acme",
|
|
77
|
-
artifact,
|
|
78
|
-
visibility: ApiResourceVisibility.visibility_org,
|
|
79
|
-
message: "big",
|
|
80
|
-
}),
|
|
81
|
-
);
|
|
82
|
-
|
|
83
|
-
expect(captured.mints).toBe(1);
|
|
84
|
-
expect(record.url).toBe(STAGING_URL);
|
|
85
|
-
expect(record.bytes).toBe(artifact.length);
|
|
86
|
-
const pushed = captured.pushes[0]!;
|
|
87
|
-
expect(pushed.artifact.length).toBe(0);
|
|
88
|
-
expect(pushed.artifactUploadRef).toBe("sau_p");
|
|
89
|
-
expect(pushed.visibility).toBe(ApiResourceVisibility.visibility_org);
|
|
90
|
-
expect(pushed.message).toBe("big");
|
|
91
|
-
});
|
|
92
|
-
});
|
|
@@ -1,118 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Pins the edition vocabulary (`resource-availability.ts`): the one
|
|
3
|
-
* edition-to-mode converter, the rank comparison behind
|
|
4
|
-
* `isResourceAvailable`, and the two properties the DDs assumed and this
|
|
5
|
-
* module has to make true —
|
|
6
|
-
*
|
|
7
|
-
* - ranks, never wire numbers: `enterprise = 3` sits ABOVE `cloud = 2`
|
|
8
|
-
* and `cloud_only = 2` on the wire, so a comparison on enum values
|
|
9
|
-
* would say an Enterprise-tier kind is not served by a Cloud server;
|
|
10
|
-
* - forward compatibility: an edition value this SDK does not know
|
|
11
|
-
* (a newer server) maps to `"cloud"` instead of throwing, so an older
|
|
12
|
-
* console never breaks against a newer server.
|
|
13
|
-
*
|
|
14
|
-
* The kinds named here are chosen one per tier; re-tiering any of them is
|
|
15
|
-
* a contract change and must touch this file (editions program, DD-001).
|
|
16
|
-
*/
|
|
17
|
-
import { describe, expect, it } from "vitest";
|
|
18
|
-
import { ApiResourceKind } from "@stigmer/protos/ai/stigmer/commons/apiresource/apiresourcekind/api_resource_kind_pb";
|
|
19
|
-
import { ServerEdition } from "@stigmer/protos/ai/stigmer/platform/v1/server_info_pb";
|
|
20
|
-
|
|
21
|
-
import {
|
|
22
|
-
deploymentModeOf,
|
|
23
|
-
isResourceAvailable,
|
|
24
|
-
type DeploymentMode,
|
|
25
|
-
} from "../resource-availability";
|
|
26
|
-
|
|
27
|
-
const MODES: readonly DeploymentMode[] = ["local", "enterprise", "cloud"];
|
|
28
|
-
|
|
29
|
-
describe("deploymentModeOf — the one edition-to-mode converter", () => {
|
|
30
|
-
it("maps each known edition to its mode", () => {
|
|
31
|
-
expect(deploymentModeOf(ServerEdition.oss)).toBe("local");
|
|
32
|
-
expect(deploymentModeOf(ServerEdition.enterprise)).toBe("enterprise");
|
|
33
|
-
expect(deploymentModeOf(ServerEdition.cloud)).toBe("cloud");
|
|
34
|
-
});
|
|
35
|
-
|
|
36
|
-
it("maps unspecified to cloud — the documented safe default (nothing hidden on a broken server)", () => {
|
|
37
|
-
expect(deploymentModeOf(ServerEdition.server_edition_unspecified)).toBe(
|
|
38
|
-
"cloud",
|
|
39
|
-
);
|
|
40
|
-
});
|
|
41
|
-
|
|
42
|
-
it("maps an edition this SDK does not know to cloud instead of throwing — older client, newer server", () => {
|
|
43
|
-
// A future fourth edition arrives off the wire as a number the enum
|
|
44
|
-
// type does not name. The cast is the test's point.
|
|
45
|
-
expect(deploymentModeOf(99 as ServerEdition)).toBe("cloud");
|
|
46
|
-
});
|
|
47
|
-
});
|
|
48
|
-
|
|
49
|
-
describe("isResourceAvailable — a tier is a minimum edition", () => {
|
|
50
|
-
it("open_source-tier kinds are available in every mode", () => {
|
|
51
|
-
for (const mode of MODES) {
|
|
52
|
-
expect(isResourceAvailable(ApiResourceKind.agent, mode), mode).toBe(true);
|
|
53
|
-
}
|
|
54
|
-
});
|
|
55
|
-
|
|
56
|
-
it("enterprise-tier kinds are available in enterprise and cloud, not local", () => {
|
|
57
|
-
// `invitation` is the example since `iam_policy` moved to open_source
|
|
58
|
-
// (20260913.01: the row half is served by every edition).
|
|
59
|
-
expect(isResourceAvailable(ApiResourceKind.invitation, "local")).toBe(
|
|
60
|
-
false,
|
|
61
|
-
);
|
|
62
|
-
expect(isResourceAvailable(ApiResourceKind.invitation, "enterprise")).toBe(
|
|
63
|
-
true,
|
|
64
|
-
);
|
|
65
|
-
// The inversion case: enterprise = 3 > cloud = 2 on the wire. A
|
|
66
|
-
// wire-number comparison fails exactly here.
|
|
67
|
-
expect(isResourceAvailable(ApiResourceKind.invitation, "cloud")).toBe(true);
|
|
68
|
-
});
|
|
69
|
-
|
|
70
|
-
it("iam_policy is open_source since the row half moved into open source — served everywhere", () => {
|
|
71
|
-
for (const mode of MODES) {
|
|
72
|
-
expect(isResourceAvailable(ApiResourceKind.iam_policy, mode), mode).toBe(
|
|
73
|
-
true,
|
|
74
|
-
);
|
|
75
|
-
}
|
|
76
|
-
});
|
|
77
|
-
|
|
78
|
-
it("cloud_only-tier kinds are available in cloud only", () => {
|
|
79
|
-
expect(
|
|
80
|
-
isResourceAvailable(ApiResourceKind.api_resource_version, "local"),
|
|
81
|
-
).toBe(false);
|
|
82
|
-
expect(
|
|
83
|
-
isResourceAvailable(ApiResourceKind.api_resource_version, "enterprise"),
|
|
84
|
-
).toBe(false);
|
|
85
|
-
expect(
|
|
86
|
-
isResourceAvailable(ApiResourceKind.api_resource_version, "cloud"),
|
|
87
|
-
).toBe(true);
|
|
88
|
-
});
|
|
89
|
-
|
|
90
|
-
it("the kinds this entry re-tiers read as their new tier", () => {
|
|
91
|
-
// oauth_app: served by the OSS server; the cloud_only tier was drift.
|
|
92
|
-
expect(isResourceAvailable(ApiResourceKind.oauth_app, "local")).toBe(true);
|
|
93
|
-
// platform: the operator seat a self-hosting Enterprise company owns.
|
|
94
|
-
expect(isResourceAvailable(ApiResourceKind.platform, "local")).toBe(false);
|
|
95
|
-
expect(isResourceAvailable(ApiResourceKind.platform, "enterprise")).toBe(
|
|
96
|
-
true,
|
|
97
|
-
);
|
|
98
|
-
// identity_account: open_source since the open-source server serves the
|
|
99
|
-
// domain (20260911.11 slice 5); the tier moved in the same change as
|
|
100
|
-
// the serving code, never ahead of it.
|
|
101
|
-
expect(isResourceAvailable(ApiResourceKind.identity_account, "local")).toBe(
|
|
102
|
-
true,
|
|
103
|
-
);
|
|
104
|
-
// agent_share and channel_app: served by OSS; they never moved.
|
|
105
|
-
expect(isResourceAvailable(ApiResourceKind.agent_share, "local")).toBe(
|
|
106
|
-
true,
|
|
107
|
-
);
|
|
108
|
-
expect(isResourceAvailable(ApiResourceKind.channel_app, "local")).toBe(
|
|
109
|
-
true,
|
|
110
|
-
);
|
|
111
|
-
});
|
|
112
|
-
|
|
113
|
-
it("refuses a kind with no tier — a programming error, never silently available", () => {
|
|
114
|
-
expect(() =>
|
|
115
|
-
isResourceAvailable(ApiResourceKind.api_resource_kind_unknown, "cloud"),
|
|
116
|
-
).toThrow(/no tier/);
|
|
117
|
-
});
|
|
118
|
-
});
|
|
@@ -1,122 +0,0 @@
|
|
|
1
|
-
import { describe, it, expect, vi } from "vitest";
|
|
2
|
-
import {
|
|
3
|
-
createRunnerAdapter,
|
|
4
|
-
type RunnerWorkerHost,
|
|
5
|
-
} from "../runner-adapter";
|
|
6
|
-
|
|
7
|
-
function createMockHost(): RunnerWorkerHost & {
|
|
8
|
-
addSession: ReturnType<typeof vi.fn>;
|
|
9
|
-
removeSession: ReturnType<typeof vi.fn>;
|
|
10
|
-
addWorkflowExecution: ReturnType<typeof vi.fn>;
|
|
11
|
-
removeWorkflowExecution: ReturnType<typeof vi.fn>;
|
|
12
|
-
} {
|
|
13
|
-
return {
|
|
14
|
-
addSession: vi.fn().mockResolvedValue(undefined),
|
|
15
|
-
removeSession: vi.fn().mockResolvedValue(undefined),
|
|
16
|
-
addWorkflowExecution: vi.fn().mockResolvedValue(undefined),
|
|
17
|
-
removeWorkflowExecution: vi.fn().mockResolvedValue(undefined),
|
|
18
|
-
};
|
|
19
|
-
}
|
|
20
|
-
|
|
21
|
-
describe("createRunnerAdapter", () => {
|
|
22
|
-
it("returns an adapter with all four lifecycle methods", () => {
|
|
23
|
-
const adapter = createRunnerAdapter(createMockHost());
|
|
24
|
-
|
|
25
|
-
expect(adapter.onSessionOpened).toBeInstanceOf(Function);
|
|
26
|
-
expect(adapter.onSessionClosed).toBeInstanceOf(Function);
|
|
27
|
-
expect(adapter.onWorkflowExecutionCreated).toBeInstanceOf(Function);
|
|
28
|
-
expect(adapter.onWorkflowExecutionTerminated).toBeInstanceOf(Function);
|
|
29
|
-
});
|
|
30
|
-
|
|
31
|
-
it("maps onSessionOpened to host.addSession with the session id", async () => {
|
|
32
|
-
const host = createMockHost();
|
|
33
|
-
const adapter = createRunnerAdapter(host);
|
|
34
|
-
|
|
35
|
-
await adapter.onSessionOpened("ses-123");
|
|
36
|
-
|
|
37
|
-
expect(host.addSession).toHaveBeenCalledTimes(1);
|
|
38
|
-
expect(host.addSession).toHaveBeenCalledWith("ses-123");
|
|
39
|
-
// The asymmetric mapping is the footgun this factory exists to prevent:
|
|
40
|
-
// closing/removing must not fire on open.
|
|
41
|
-
expect(host.removeSession).not.toHaveBeenCalled();
|
|
42
|
-
});
|
|
43
|
-
|
|
44
|
-
it("maps onSessionClosed to host.removeSession with the session id", async () => {
|
|
45
|
-
const host = createMockHost();
|
|
46
|
-
const adapter = createRunnerAdapter(host);
|
|
47
|
-
|
|
48
|
-
await adapter.onSessionClosed("ses-123");
|
|
49
|
-
|
|
50
|
-
expect(host.removeSession).toHaveBeenCalledTimes(1);
|
|
51
|
-
expect(host.removeSession).toHaveBeenCalledWith("ses-123");
|
|
52
|
-
expect(host.addSession).not.toHaveBeenCalled();
|
|
53
|
-
});
|
|
54
|
-
|
|
55
|
-
it("maps onWorkflowExecutionCreated to host.addWorkflowExecution with the execution id", async () => {
|
|
56
|
-
const host = createMockHost();
|
|
57
|
-
const adapter = createRunnerAdapter(host);
|
|
58
|
-
|
|
59
|
-
await adapter.onWorkflowExecutionCreated("wfexec-456");
|
|
60
|
-
|
|
61
|
-
expect(host.addWorkflowExecution).toHaveBeenCalledTimes(1);
|
|
62
|
-
expect(host.addWorkflowExecution).toHaveBeenCalledWith("wfexec-456");
|
|
63
|
-
expect(host.removeWorkflowExecution).not.toHaveBeenCalled();
|
|
64
|
-
});
|
|
65
|
-
|
|
66
|
-
it("maps onWorkflowExecutionTerminated to host.removeWorkflowExecution with the execution id", async () => {
|
|
67
|
-
const host = createMockHost();
|
|
68
|
-
const adapter = createRunnerAdapter(host);
|
|
69
|
-
|
|
70
|
-
await adapter.onWorkflowExecutionTerminated("wfexec-456");
|
|
71
|
-
|
|
72
|
-
expect(host.removeWorkflowExecution).toHaveBeenCalledTimes(1);
|
|
73
|
-
expect(host.removeWorkflowExecution).toHaveBeenCalledWith("wfexec-456");
|
|
74
|
-
expect(host.addWorkflowExecution).not.toHaveBeenCalled();
|
|
75
|
-
});
|
|
76
|
-
|
|
77
|
-
it("resolves to undefined regardless of the host's return value", async () => {
|
|
78
|
-
// The host's add methods return a task queue string; the adapter contract
|
|
79
|
-
// is Promise<void>, so the value must be swallowed.
|
|
80
|
-
const host = createMockHost();
|
|
81
|
-
host.addSession.mockResolvedValue("session:ses-123");
|
|
82
|
-
host.addWorkflowExecution.mockResolvedValue("wfexec:wfexec-456");
|
|
83
|
-
const adapter = createRunnerAdapter(host);
|
|
84
|
-
|
|
85
|
-
await expect(adapter.onSessionOpened("ses-123")).resolves.toBeUndefined();
|
|
86
|
-
await expect(
|
|
87
|
-
adapter.onWorkflowExecutionCreated("wfexec-456"),
|
|
88
|
-
).resolves.toBeUndefined();
|
|
89
|
-
});
|
|
90
|
-
|
|
91
|
-
it("awaits the host: it does not resolve before the host settles", async () => {
|
|
92
|
-
let release!: () => void;
|
|
93
|
-
const gate = new Promise<void>((resolve) => {
|
|
94
|
-
release = resolve;
|
|
95
|
-
});
|
|
96
|
-
const host = createMockHost();
|
|
97
|
-
host.addSession.mockReturnValue(gate);
|
|
98
|
-
const adapter = createRunnerAdapter(host);
|
|
99
|
-
|
|
100
|
-
let settled = false;
|
|
101
|
-
const pending = adapter.onSessionOpened("ses-123").then(() => {
|
|
102
|
-
settled = true;
|
|
103
|
-
});
|
|
104
|
-
|
|
105
|
-
await Promise.resolve();
|
|
106
|
-
expect(settled).toBe(false);
|
|
107
|
-
|
|
108
|
-
release();
|
|
109
|
-
await pending;
|
|
110
|
-
expect(settled).toBe(true);
|
|
111
|
-
});
|
|
112
|
-
|
|
113
|
-
it("propagates a host rejection", async () => {
|
|
114
|
-
const host = createMockHost();
|
|
115
|
-
host.removeSession.mockRejectedValue(new Error("worker teardown failed"));
|
|
116
|
-
const adapter = createRunnerAdapter(host);
|
|
117
|
-
|
|
118
|
-
await expect(adapter.onSessionClosed("ses-123")).rejects.toThrow(
|
|
119
|
-
"worker teardown failed",
|
|
120
|
-
);
|
|
121
|
-
});
|
|
122
|
-
});
|
|
@@ -1,66 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Unit tests for the hand-written session utilities: the pinned
|
|
3
|
-
* session-context metadata key and the typed-context merge semantics.
|
|
4
|
-
*/
|
|
5
|
-
|
|
6
|
-
import { describe, it, expect } from "vitest";
|
|
7
|
-
import {
|
|
8
|
-
SESSION_CONTEXT_METADATA_KEY,
|
|
9
|
-
mergeSessionContext,
|
|
10
|
-
} from "../session.js";
|
|
11
|
-
|
|
12
|
-
describe("SESSION_CONTEXT_METADATA_KEY", () => {
|
|
13
|
-
it("is pinned verbatim to the runner's constant (mirror guard)", () => {
|
|
14
|
-
// Pinned to SESSION_CONTEXT_METADATA_KEY in
|
|
15
|
-
// backend/services/runner/src/shared/session-context.ts. Changing
|
|
16
|
-
// either side alone silently blinds the agent to the embedder's
|
|
17
|
-
// context; change BOTH together.
|
|
18
|
-
expect(SESSION_CONTEXT_METADATA_KEY).toBe("stigmer.ai/session-context");
|
|
19
|
-
});
|
|
20
|
-
});
|
|
21
|
-
|
|
22
|
-
describe("mergeSessionContext", () => {
|
|
23
|
-
it("folds the context into the metadata map under the reserved key", () => {
|
|
24
|
-
expect(mergeSessionContext({ "acme/tenant": "t-1" }, "Role: admin")).toEqual({
|
|
25
|
-
"acme/tenant": "t-1",
|
|
26
|
-
[SESSION_CONTEXT_METADATA_KEY]: "Role: admin",
|
|
27
|
-
});
|
|
28
|
-
});
|
|
29
|
-
|
|
30
|
-
it("creates the map when metadata is undefined", () => {
|
|
31
|
-
expect(mergeSessionContext(undefined, "Role: admin")).toEqual({
|
|
32
|
-
[SESSION_CONTEXT_METADATA_KEY]: "Role: admin",
|
|
33
|
-
});
|
|
34
|
-
});
|
|
35
|
-
|
|
36
|
-
it("lets the typed field win over a raw entry under the reserved key", () => {
|
|
37
|
-
expect(
|
|
38
|
-
mergeSessionContext(
|
|
39
|
-
{ [SESSION_CONTEXT_METADATA_KEY]: "stale raw value" },
|
|
40
|
-
"typed value",
|
|
41
|
-
),
|
|
42
|
-
).toEqual({ [SESSION_CONTEXT_METADATA_KEY]: "typed value" });
|
|
43
|
-
});
|
|
44
|
-
|
|
45
|
-
it("returns metadata untouched when the context is undefined", () => {
|
|
46
|
-
const metadata = { "acme/tenant": "t-1" };
|
|
47
|
-
expect(mergeSessionContext(metadata, undefined)).toBe(metadata);
|
|
48
|
-
});
|
|
49
|
-
|
|
50
|
-
it("returns undefined when both inputs are absent — callers never send an empty map", () => {
|
|
51
|
-
expect(mergeSessionContext(undefined, undefined)).toBeUndefined();
|
|
52
|
-
expect(mergeSessionContext(undefined, " ")).toBeUndefined();
|
|
53
|
-
});
|
|
54
|
-
|
|
55
|
-
it("trims the context before storing (blank means absent)", () => {
|
|
56
|
-
expect(mergeSessionContext(undefined, " Role: admin ")).toEqual({
|
|
57
|
-
[SESSION_CONTEXT_METADATA_KEY]: "Role: admin",
|
|
58
|
-
});
|
|
59
|
-
});
|
|
60
|
-
|
|
61
|
-
it("does not mutate the caller's metadata map", () => {
|
|
62
|
-
const metadata = { "acme/tenant": "t-1" };
|
|
63
|
-
mergeSessionContext(metadata, "Role: admin");
|
|
64
|
-
expect(metadata).toEqual({ "acme/tenant": "t-1" });
|
|
65
|
-
});
|
|
66
|
-
});
|
|
@@ -1,159 +0,0 @@
|
|
|
1
|
-
// Unit tests for the framework-free agent-sharing helpers: origin
|
|
2
|
-
// validation (mirror of the proto CEL rule) and the hosted-link / embed
|
|
3
|
-
// snippet builders shared by the web console, desktop app, and CLI.
|
|
4
|
-
|
|
5
|
-
import { describe, expect, it } from "vitest";
|
|
6
|
-
import {
|
|
7
|
-
LINK_TOKEN_PARAM,
|
|
8
|
-
MAX_ALLOWED_ORIGINS,
|
|
9
|
-
appendLinkToken,
|
|
10
|
-
buildChatUrl,
|
|
11
|
-
buildEmbedLoaderUrl,
|
|
12
|
-
buildEmbedSnippet,
|
|
13
|
-
chatPath,
|
|
14
|
-
validateOrigin,
|
|
15
|
-
} from "../sharing";
|
|
16
|
-
|
|
17
|
-
describe("validateOrigin", () => {
|
|
18
|
-
it("accepts exact web origins", () => {
|
|
19
|
-
expect(validateOrigin("https://example.com")).toBeNull();
|
|
20
|
-
expect(validateOrigin("http://example.com")).toBeNull();
|
|
21
|
-
expect(validateOrigin("https://sub.example.com")).toBeNull();
|
|
22
|
-
expect(validateOrigin("https://example.com:8443")).toBeNull();
|
|
23
|
-
expect(validateOrigin("http://localhost:3000")).toBeNull();
|
|
24
|
-
});
|
|
25
|
-
|
|
26
|
-
it("trims surrounding whitespace before validating", () => {
|
|
27
|
-
expect(validateOrigin(" https://example.com ")).toBeNull();
|
|
28
|
-
});
|
|
29
|
-
|
|
30
|
-
it("rejects empty input with guidance", () => {
|
|
31
|
-
expect(validateOrigin("")).toMatch(/Enter an origin/);
|
|
32
|
-
expect(validateOrigin(" ")).toMatch(/Enter an origin/);
|
|
33
|
-
});
|
|
34
|
-
|
|
35
|
-
it("rejects trailing slashes, paths, queries, and fragments", () => {
|
|
36
|
-
for (const bad of [
|
|
37
|
-
"https://example.com/",
|
|
38
|
-
"https://example.com/path",
|
|
39
|
-
"https://example.com?q=1",
|
|
40
|
-
"https://example.com#top",
|
|
41
|
-
]) {
|
|
42
|
-
expect(validateOrigin(bad)).toMatch(/exact web origin/);
|
|
43
|
-
}
|
|
44
|
-
});
|
|
45
|
-
|
|
46
|
-
it("rejects non-http(s) schemes and bare hosts", () => {
|
|
47
|
-
expect(validateOrigin("ftp://example.com")).toMatch(/exact web origin/);
|
|
48
|
-
expect(validateOrigin("example.com")).toMatch(/exact web origin/);
|
|
49
|
-
});
|
|
50
|
-
|
|
51
|
-
it("rejects hostname labels with leading/trailing hyphens", () => {
|
|
52
|
-
expect(validateOrigin("https://-bad.example.com")).toMatch(/exact web origin/);
|
|
53
|
-
expect(validateOrigin("https://bad-.example.com")).toMatch(/exact web origin/);
|
|
54
|
-
});
|
|
55
|
-
|
|
56
|
-
it("exposes the proto max_items bound", () => {
|
|
57
|
-
expect(MAX_ALLOWED_ORIGINS).toBe(32);
|
|
58
|
-
});
|
|
59
|
-
});
|
|
60
|
-
|
|
61
|
-
describe("chatPath / buildChatUrl", () => {
|
|
62
|
-
it("builds the canonical /chat/<org>/<slug> path", () => {
|
|
63
|
-
expect(chatPath("acme", "support-agent")).toBe("/chat/acme/support-agent");
|
|
64
|
-
});
|
|
65
|
-
|
|
66
|
-
it("builds the absolute hosted chat URL", () => {
|
|
67
|
-
expect(buildChatUrl("https://app.stigmer.ai", "acme", "support-agent")).toBe(
|
|
68
|
-
"https://app.stigmer.ai/chat/acme/support-agent",
|
|
69
|
-
);
|
|
70
|
-
});
|
|
71
|
-
|
|
72
|
-
it("tolerates a trailing slash on the origin", () => {
|
|
73
|
-
expect(buildChatUrl("https://app.stigmer.ai/", "acme", "support-agent")).toBe(
|
|
74
|
-
"https://app.stigmer.ai/chat/acme/support-agent",
|
|
75
|
-
);
|
|
76
|
-
});
|
|
77
|
-
|
|
78
|
-
it("works with localhost origins (local backend)", () => {
|
|
79
|
-
expect(buildChatUrl("http://localhost:8234", "stigmer", "helper")).toBe(
|
|
80
|
-
"http://localhost:8234/chat/stigmer/helper",
|
|
81
|
-
);
|
|
82
|
-
});
|
|
83
|
-
|
|
84
|
-
it("appends ?k= when the share link is locked with a token", () => {
|
|
85
|
-
expect(chatPath("acme", "support-agent", "tok123")).toBe(
|
|
86
|
-
"/chat/acme/support-agent?k=tok123",
|
|
87
|
-
);
|
|
88
|
-
expect(
|
|
89
|
-
buildChatUrl("https://app.stigmer.ai", "acme", "support-agent", "tok123"),
|
|
90
|
-
).toBe("https://app.stigmer.ai/chat/acme/support-agent?k=tok123");
|
|
91
|
-
});
|
|
92
|
-
|
|
93
|
-
it("url-encodes the token (defense in depth; generated tokens are url-safe)", () => {
|
|
94
|
-
expect(chatPath("acme", "bot", "a+b/c")).toBe("/chat/acme/bot?k=a%2Bb%2Fc");
|
|
95
|
-
});
|
|
96
|
-
|
|
97
|
-
it("omits ?k= for an empty/undefined token (plain link)", () => {
|
|
98
|
-
expect(chatPath("acme", "bot", "")).toBe("/chat/acme/bot");
|
|
99
|
-
expect(chatPath("acme", "bot", undefined)).toBe("/chat/acme/bot");
|
|
100
|
-
});
|
|
101
|
-
});
|
|
102
|
-
|
|
103
|
-
describe("appendLinkToken", () => {
|
|
104
|
-
it("appends the identical ?k= shape chatPath emits", () => {
|
|
105
|
-
expect(appendLinkToken("https://app.stigmer.ai/chat/acme/bot", "tok123")).toBe(
|
|
106
|
-
buildChatUrl("https://app.stigmer.ai", "acme", "bot", "tok123"),
|
|
107
|
-
);
|
|
108
|
-
});
|
|
109
|
-
|
|
110
|
-
it("uses & when the URL already carries a query", () => {
|
|
111
|
-
expect(appendLinkToken("/chat/acme/bot?theme=dark", "tok123")).toBe(
|
|
112
|
-
`/chat/acme/bot?theme=dark&${LINK_TOKEN_PARAM}=tok123`,
|
|
113
|
-
);
|
|
114
|
-
});
|
|
115
|
-
|
|
116
|
-
it("returns the URL unchanged for a null/empty token", () => {
|
|
117
|
-
expect(appendLinkToken("/chat/acme/bot", null)).toBe("/chat/acme/bot");
|
|
118
|
-
expect(appendLinkToken("/chat/acme/bot", undefined)).toBe("/chat/acme/bot");
|
|
119
|
-
expect(appendLinkToken("/chat/acme/bot", "")).toBe("/chat/acme/bot");
|
|
120
|
-
});
|
|
121
|
-
});
|
|
122
|
-
|
|
123
|
-
describe("buildEmbedLoaderUrl", () => {
|
|
124
|
-
it("points at embed.js on the app origin root", () => {
|
|
125
|
-
expect(buildEmbedLoaderUrl("https://app.stigmer.ai")).toBe("https://app.stigmer.ai/embed.js");
|
|
126
|
-
});
|
|
127
|
-
|
|
128
|
-
it("tolerates a trailing slash on the origin", () => {
|
|
129
|
-
expect(buildEmbedLoaderUrl("https://app.stigmer.ai/")).toBe("https://app.stigmer.ai/embed.js");
|
|
130
|
-
});
|
|
131
|
-
});
|
|
132
|
-
|
|
133
|
-
describe("buildEmbedSnippet", () => {
|
|
134
|
-
it("emits exactly the two-line loader + element snippet", () => {
|
|
135
|
-
expect(buildEmbedSnippet("https://app.stigmer.ai", "acme", "support-agent")).toBe(
|
|
136
|
-
[
|
|
137
|
-
`<script src="https://app.stigmer.ai/embed.js" async></script>`,
|
|
138
|
-
`<stigmer-agent org="acme" agent="support-agent"></stigmer-agent>`,
|
|
139
|
-
].join("\n"),
|
|
140
|
-
);
|
|
141
|
-
});
|
|
142
|
-
|
|
143
|
-
it("adds the token attribute when the share link is locked", () => {
|
|
144
|
-
expect(
|
|
145
|
-
buildEmbedSnippet("https://app.stigmer.ai", "acme", "support-agent", "tok123"),
|
|
146
|
-
).toBe(
|
|
147
|
-
[
|
|
148
|
-
`<script src="https://app.stigmer.ai/embed.js" async></script>`,
|
|
149
|
-
`<stigmer-agent org="acme" agent="support-agent" token="tok123"></stigmer-agent>`,
|
|
150
|
-
].join("\n"),
|
|
151
|
-
);
|
|
152
|
-
});
|
|
153
|
-
|
|
154
|
-
it("omits the token attribute for an empty token (plain link)", () => {
|
|
155
|
-
expect(buildEmbedSnippet("https://app.stigmer.ai", "acme", "bot", "")).toBe(
|
|
156
|
-
buildEmbedSnippet("https://app.stigmer.ai", "acme", "bot"),
|
|
157
|
-
);
|
|
158
|
-
});
|
|
159
|
-
});
|