@ory/argus 0.14.0 → 1.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +31 -46
- package/assets/commands/temporal-up.md +1 -1
- package/assets/skills/auth-setup/SKILL.md +1 -1
- package/assets/skills/local-dev/SKILL.md +17 -7
- package/assets/skills/ory-build-agent/SKILL.md +39 -91
- package/assets/skills/ory-e2b-sandbox/SKILL.md +18 -17
- package/assets/skills/ory-temporal-worker/SKILL.md +31 -33
- package/assets/skills/permissions-onboarding/SKILL.md +131 -104
- package/dist/adapters.d.ts +88 -32
- package/dist/adapters.js +443 -164
- package/dist/agent-auth.d.ts +226 -67
- package/dist/agent-auth.js +951 -205
- package/dist/auth-store.d.ts +37 -2
- package/dist/auth-store.js +37 -3
- package/dist/auth.d.ts +33 -4
- package/dist/auth.js +163 -20
- package/dist/bash-parser.d.ts +98 -0
- package/dist/bash-parser.js +396 -0
- package/dist/branding.d.ts +77 -16
- package/dist/branding.js +93 -23
- package/dist/build-info.json +4 -4
- package/dist/cli-invocation.d.ts +1 -1
- package/dist/cli-invocation.js +2 -1
- package/dist/cli.d.ts +20 -29
- package/dist/cli.js +271 -239
- package/dist/client.d.ts +175 -138
- package/dist/client.js +672 -391
- package/dist/config.d.ts +217 -54
- package/dist/config.js +461 -42
- package/dist/context.d.ts +10 -0
- package/dist/context.js +21 -0
- package/dist/contract-suite.d.ts +3 -5
- package/dist/contract-suite.js +75 -47
- package/dist/denial.d.ts +36 -3
- package/dist/denial.js +79 -10
- package/dist/event-reporter.d.ts +77 -0
- package/dist/event-reporter.js +776 -0
- package/dist/external-registrations-main.d.ts +10 -0
- package/dist/external-registrations-main.js +38 -0
- package/dist/external-registrations.d.ts +79 -0
- package/dist/external-registrations.js +188 -0
- package/dist/help-cli.d.ts +39 -0
- package/dist/help-cli.js +55 -0
- package/dist/hook-timeout.d.ts +64 -0
- package/dist/hook-timeout.js +88 -0
- package/dist/index.d.ts +28 -23
- package/dist/index.js +173 -58
- package/dist/lifecycle.d.ts +3 -3
- package/dist/lifecycle.js +38 -6
- package/dist/local/cli.js +11 -6
- package/dist/local/configs.d.ts +74 -18
- package/dist/local/configs.js +291 -84
- package/dist/local/health.js +7 -7
- package/dist/local/index.d.ts +2 -2
- package/dist/local/index.js +24 -10
- package/dist/local/manager.d.ts +20 -1
- package/dist/local/manager.js +159 -36
- package/dist/local/ports.d.ts +158 -0
- package/dist/local/ports.js +443 -0
- package/dist/local/seed.d.ts +13 -5
- package/dist/local/seed.js +62 -38
- package/dist/logger.d.ts +54 -25
- package/dist/logger.js +329 -63
- package/dist/mcp.d.ts +2 -2
- package/dist/mcp.js +10 -5
- package/dist/mirror-bootstrap.d.ts +48 -0
- package/dist/mirror-bootstrap.js +254 -0
- package/dist/opl.d.ts +289 -0
- package/dist/opl.js +446 -0
- package/dist/permission-mode.d.ts +87 -0
- package/dist/permission-mode.js +307 -0
- package/dist/permissions-cli.d.ts +13 -49
- package/dist/permissions-cli.js +154 -348
- package/dist/permissions.d.ts +148 -38
- package/dist/permissions.js +591 -45
- package/dist/post-install.d.ts +33 -0
- package/dist/post-install.js +127 -0
- package/dist/read-credential.d.ts +65 -0
- package/dist/read-credential.js +86 -0
- package/dist/registry/cli.js +5 -2
- package/dist/registry/config.d.ts +0 -17
- package/dist/registry/config.js +0 -23
- package/dist/registry/index.d.ts +1 -1
- package/dist/registry/index.js +2 -2
- package/dist/registry/manager.d.ts +4 -21
- package/dist/registry/manager.js +21 -37
- package/dist/runtime-credential.d.ts +140 -0
- package/dist/runtime-credential.js +572 -0
- package/dist/runtime.d.ts +413 -0
- package/dist/runtime.js +825 -0
- package/dist/setup.d.ts +23 -47
- package/dist/setup.js +59 -116
- package/dist/skills.js +0 -7
- package/dist/status-cli.d.ts +27 -11
- package/dist/status-cli.js +121 -115
- package/dist/status-data.d.ts +116 -17
- package/dist/status-data.js +121 -38
- package/dist/subject.d.ts +126 -20
- package/dist/subject.js +215 -30
- package/dist/testing.d.ts +74 -38
- package/dist/testing.js +185 -68
- package/dist/tool-catalog.d.ts +53 -11
- package/dist/tool-catalog.js +164 -13
- package/dist/tool-metadata.d.ts +7 -6
- package/dist/tool-metadata.js +6 -5
- package/dist/types.d.ts +11 -1
- package/dist/uninstall.d.ts +71 -34
- package/dist/uninstall.js +217 -85
- package/dist/user-login.d.ts +9 -10
- package/dist/user-login.js +56 -75
- package/dist/watch-cli.d.ts +6 -0
- package/dist/watch-cli.js +217 -0
- package/package.json +4 -27
- package/assets/commands/dashboard.md +0 -34
- package/dist/dashboard-cli.d.ts +0 -8
- package/dist/dashboard-cli.js +0 -70
- package/dist/dev.d.ts +0 -103
- package/dist/dev.js +0 -583
- package/dist/interactive-setup.d.ts +0 -286
- package/dist/interactive-setup.js +0 -1734
- package/dist/local/jaeger-main.d.ts +0 -13
- package/dist/local/jaeger-main.js +0 -85
- package/dist/local/jaeger.d.ts +0 -50
- package/dist/local/jaeger.js +0 -162
- package/dist/otel/exporter.d.ts +0 -17
- package/dist/otel/exporter.js +0 -12
- package/dist/otel/index.d.ts +0 -2
- package/dist/otel/index.js +0 -8
- package/dist/otel/otlp.d.ts +0 -103
- package/dist/otel/otlp.js +0 -385
- package/dist/project-api-key.d.ts +0 -69
- package/dist/project-api-key.js +0 -147
- package/dist/setup-actions.d.ts +0 -232
- package/dist/setup-actions.js +0 -507
- package/dist/tracer.d.ts +0 -190
- package/dist/tracer.js +0 -481
- package/dist/watch-sandbox.d.ts +0 -9
- package/dist/watch-sandbox.js +0 -81
- package/dist/web/api.d.ts +0 -33
- package/dist/web/api.js +0 -294
- package/dist/web/launch.d.ts +0 -11
- package/dist/web/launch.js +0 -96
- package/dist/web/server.d.ts +0 -20
- package/dist/web/server.js +0 -233
- package/dist/web/types.d.ts +0 -65
- package/dist/web/types.js +0 -2
- package/dist/webapp/assets/index-Wucl4SZs.css +0 -1
- package/dist/webapp/assets/index-m-GtEdq0.js +0 -49
- package/dist/webapp/favicon.ico +0 -0
- package/dist/webapp/index.html +0 -15
|
@@ -0,0 +1,443 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Host-facing addressing for the local Ory stack — which ports it publishes on
|
|
4
|
+
* the host, and which host name everything else should use to reach it.
|
|
5
|
+
*
|
|
6
|
+
* Two kinds of port live in this stack, and conflating them is the bug this
|
|
7
|
+
* module exists to prevent:
|
|
8
|
+
*
|
|
9
|
+
* - **Container-internal ports** are what each service listens on *inside* the
|
|
10
|
+
* compose network, and what one service uses to address another
|
|
11
|
+
* (`http://kratos:4433`). They live on a private bridge network, so they can
|
|
12
|
+
* never collide with anything on the host and there is no reason to make them
|
|
13
|
+
* configurable. They are fixed constants below.
|
|
14
|
+
* - **Host ports** are the left-hand side of a compose `ports:` mapping — the
|
|
15
|
+
* only ports that are actually claimed on the developer's machine, and so the
|
|
16
|
+
* only ones that can collide. Every one of them is overridable.
|
|
17
|
+
*
|
|
18
|
+
* The defaults are the stock upstream Ory ports (4433/4434, 4444/4445,
|
|
19
|
+
* 4466/4467, …), which is deliberate — they are the ports every Ory doc and
|
|
20
|
+
* tutorial uses. It also means a developer who already runs Ory locally, which
|
|
21
|
+
* is precisely this stack's audience, collides on first run. Before #63 there
|
|
22
|
+
* was no override and no diagnosis: `docker compose up` failed with Docker's
|
|
23
|
+
* raw "port is already allocated" and the only apparent fix was to hand-edit
|
|
24
|
+
* the generated compose file, which the next `local up` regenerates away.
|
|
25
|
+
*
|
|
26
|
+
* Three levels of control, cheapest first:
|
|
27
|
+
*
|
|
28
|
+
* 1. `ORY_LOCAL_PORT_OFFSET=100` shifts *every* default by a constant, which is
|
|
29
|
+
* the common case ("something else owns the Ory ports, move the whole
|
|
30
|
+
* stack"). Relative spacing is preserved, so the set stays collision-free
|
|
31
|
+
* with itself.
|
|
32
|
+
* 2. `ORY_LOCAL_<SERVICE>_PORT` pins one service exactly, and wins over the
|
|
33
|
+
* offset.
|
|
34
|
+
* 3. `ORY_LOCAL_HOST` changes the host every generated URL advertises, for a
|
|
35
|
+
* remote Docker daemon or an agent running inside a container. It defaults
|
|
36
|
+
* to the host parsed out of `DOCKER_HOST` when that points somewhere other
|
|
37
|
+
* than this machine, so the remote-daemon case usually needs no flag at all.
|
|
38
|
+
*/
|
|
39
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
40
|
+
if (k2 === undefined) k2 = k;
|
|
41
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
42
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
43
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
44
|
+
}
|
|
45
|
+
Object.defineProperty(o, k2, desc);
|
|
46
|
+
}) : (function(o, m, k, k2) {
|
|
47
|
+
if (k2 === undefined) k2 = k;
|
|
48
|
+
o[k2] = m[k];
|
|
49
|
+
}));
|
|
50
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
51
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
52
|
+
}) : function(o, v) {
|
|
53
|
+
o["default"] = v;
|
|
54
|
+
});
|
|
55
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
56
|
+
var ownKeys = function(o) {
|
|
57
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
58
|
+
var ar = [];
|
|
59
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
60
|
+
return ar;
|
|
61
|
+
};
|
|
62
|
+
return ownKeys(o);
|
|
63
|
+
};
|
|
64
|
+
return function (mod) {
|
|
65
|
+
if (mod && mod.__esModule) return mod;
|
|
66
|
+
var result = {};
|
|
67
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
68
|
+
__setModuleDefault(result, mod);
|
|
69
|
+
return result;
|
|
70
|
+
};
|
|
71
|
+
})();
|
|
72
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
73
|
+
exports.DEFAULT_LOCAL_HOST = exports.SKIP_PORT_CHECK_ENV_VAR = exports.LOCAL_HOST_ENV_VAR = exports.PORT_OFFSET_ENV_VAR = exports.LOCAL_PORT_SPECS = exports.LOCAL_PORT_NAMES = exports.CONSOLE_CONTAINER_PORT = exports.OATHKEEPER_API_CONTAINER_PORT = exports.OATHKEEPER_PROXY_CONTAINER_PORT = exports.LOGIN_UI_CONTAINER_PORT = exports.GATEWAY_CONTAINER_PORT = exports.HYDRA_TOKEN_USER_CONTAINER_PORT = exports.HYDRA_ADMIN_CONTAINER_PORT = exports.HYDRA_PUBLIC_CONTAINER_PORT = exports.KETO_WRITE_CONTAINER_PORT = exports.KETO_READ_CONTAINER_PORT = exports.KRATOS_ADMIN_CONTAINER_PORT = exports.KRATOS_PUBLIC_CONTAINER_PORT = void 0;
|
|
74
|
+
exports.portCheckDisabled = portCheckDisabled;
|
|
75
|
+
exports.resolveLocalPorts = resolveLocalPorts;
|
|
76
|
+
exports.hostFromDockerHost = hostFromDockerHost;
|
|
77
|
+
exports.isLoopbackHost = isLoopbackHost;
|
|
78
|
+
exports.resolveLocalHost = resolveLocalHost;
|
|
79
|
+
exports.isLocalDockerDaemon = isLocalDockerDaemon;
|
|
80
|
+
exports.hostUrl = hostUrl;
|
|
81
|
+
exports.isPortAvailable = isPortAvailable;
|
|
82
|
+
exports.findPortConflicts = findPortConflicts;
|
|
83
|
+
exports.describePortConflicts = describePortConflicts;
|
|
84
|
+
const net = __importStar(require("node:net"));
|
|
85
|
+
// ─── Container-internal ports (fixed) ──────────────────────────────
|
|
86
|
+
//
|
|
87
|
+
// Changing any of these would also mean rewriting the service's own listen
|
|
88
|
+
// config and every cross-service URL on the compose network, for no benefit:
|
|
89
|
+
// nothing outside the bridge network can see them.
|
|
90
|
+
exports.KRATOS_PUBLIC_CONTAINER_PORT = 4433;
|
|
91
|
+
exports.KRATOS_ADMIN_CONTAINER_PORT = 4434;
|
|
92
|
+
exports.KETO_READ_CONTAINER_PORT = 4466;
|
|
93
|
+
exports.KETO_WRITE_CONTAINER_PORT = 4467;
|
|
94
|
+
exports.HYDRA_PUBLIC_CONTAINER_PORT = 4444;
|
|
95
|
+
exports.HYDRA_ADMIN_CONTAINER_PORT = 4445;
|
|
96
|
+
exports.HYDRA_TOKEN_USER_CONTAINER_PORT = 5555;
|
|
97
|
+
exports.GATEWAY_CONTAINER_PORT = 4000;
|
|
98
|
+
exports.LOGIN_UI_CONTAINER_PORT = 4455;
|
|
99
|
+
exports.OATHKEEPER_PROXY_CONTAINER_PORT = 4456;
|
|
100
|
+
exports.OATHKEEPER_API_CONTAINER_PORT = 4457;
|
|
101
|
+
/** Console Lite's Dockerfile sets `ENV PORT=3000`. */
|
|
102
|
+
exports.CONSOLE_CONTAINER_PORT = 3000;
|
|
103
|
+
// ─── Host ports (overridable) ──────────────────────────────────────
|
|
104
|
+
/** Every host port the stack publishes, in the order `local status` lists them. */
|
|
105
|
+
exports.LOCAL_PORT_NAMES = [
|
|
106
|
+
"gateway",
|
|
107
|
+
"console",
|
|
108
|
+
"loginUi",
|
|
109
|
+
"kratosPublic",
|
|
110
|
+
"kratosAdmin",
|
|
111
|
+
"ketoRead",
|
|
112
|
+
"ketoWrite",
|
|
113
|
+
"hydraPublic",
|
|
114
|
+
"hydraAdmin",
|
|
115
|
+
"hydraTokenUser",
|
|
116
|
+
"oathkeeperProxy",
|
|
117
|
+
"oathkeeperApi",
|
|
118
|
+
];
|
|
119
|
+
/**
|
|
120
|
+
* The port table. `default` doubles as the container-internal port for every
|
|
121
|
+
* service, which is what keeps the generated mapping readable
|
|
122
|
+
* (`"4433:4433"` by default, `"5433:4433"` once overridden).
|
|
123
|
+
*/
|
|
124
|
+
exports.LOCAL_PORT_SPECS = {
|
|
125
|
+
gateway: {
|
|
126
|
+
default: exports.GATEWAY_CONTAINER_PORT,
|
|
127
|
+
envVar: "ORY_LOCAL_GATEWAY_PORT",
|
|
128
|
+
label: "API gateway",
|
|
129
|
+
},
|
|
130
|
+
console: {
|
|
131
|
+
default: 4100,
|
|
132
|
+
envVar: "ORY_LOCAL_CONSOLE_PORT",
|
|
133
|
+
label: "Ory Console",
|
|
134
|
+
},
|
|
135
|
+
loginUi: {
|
|
136
|
+
default: exports.LOGIN_UI_CONTAINER_PORT,
|
|
137
|
+
envVar: "ORY_LOCAL_LOGIN_UI_PORT",
|
|
138
|
+
label: "Login UI",
|
|
139
|
+
},
|
|
140
|
+
kratosPublic: {
|
|
141
|
+
default: exports.KRATOS_PUBLIC_CONTAINER_PORT,
|
|
142
|
+
envVar: "ORY_LOCAL_KRATOS_PUBLIC_PORT",
|
|
143
|
+
label: "Kratos (public)",
|
|
144
|
+
},
|
|
145
|
+
kratosAdmin: {
|
|
146
|
+
default: exports.KRATOS_ADMIN_CONTAINER_PORT,
|
|
147
|
+
envVar: "ORY_LOCAL_KRATOS_ADMIN_PORT",
|
|
148
|
+
label: "Kratos (admin)",
|
|
149
|
+
},
|
|
150
|
+
ketoRead: {
|
|
151
|
+
default: exports.KETO_READ_CONTAINER_PORT,
|
|
152
|
+
envVar: "ORY_LOCAL_KETO_READ_PORT",
|
|
153
|
+
label: "Keto (read)",
|
|
154
|
+
},
|
|
155
|
+
ketoWrite: {
|
|
156
|
+
default: exports.KETO_WRITE_CONTAINER_PORT,
|
|
157
|
+
envVar: "ORY_LOCAL_KETO_WRITE_PORT",
|
|
158
|
+
label: "Keto (write)",
|
|
159
|
+
},
|
|
160
|
+
hydraPublic: {
|
|
161
|
+
default: exports.HYDRA_PUBLIC_CONTAINER_PORT,
|
|
162
|
+
envVar: "ORY_LOCAL_HYDRA_PUBLIC_PORT",
|
|
163
|
+
label: "Hydra (public)",
|
|
164
|
+
},
|
|
165
|
+
hydraAdmin: {
|
|
166
|
+
default: exports.HYDRA_ADMIN_CONTAINER_PORT,
|
|
167
|
+
envVar: "ORY_LOCAL_HYDRA_ADMIN_PORT",
|
|
168
|
+
label: "Hydra (admin)",
|
|
169
|
+
},
|
|
170
|
+
hydraTokenUser: {
|
|
171
|
+
default: exports.HYDRA_TOKEN_USER_CONTAINER_PORT,
|
|
172
|
+
envVar: "ORY_LOCAL_HYDRA_TOKEN_USER_PORT",
|
|
173
|
+
label: "Hydra (token user)",
|
|
174
|
+
},
|
|
175
|
+
oathkeeperProxy: {
|
|
176
|
+
default: exports.OATHKEEPER_PROXY_CONTAINER_PORT,
|
|
177
|
+
envVar: "ORY_LOCAL_OATHKEEPER_PROXY_PORT",
|
|
178
|
+
label: "Oathkeeper (proxy)",
|
|
179
|
+
},
|
|
180
|
+
oathkeeperApi: {
|
|
181
|
+
default: exports.OATHKEEPER_API_CONTAINER_PORT,
|
|
182
|
+
envVar: "ORY_LOCAL_OATHKEEPER_API_PORT",
|
|
183
|
+
label: "Oathkeeper (API)",
|
|
184
|
+
},
|
|
185
|
+
};
|
|
186
|
+
/** Shifts every default port by a constant. Overridden per-port by the specific var. */
|
|
187
|
+
exports.PORT_OFFSET_ENV_VAR = "ORY_LOCAL_PORT_OFFSET";
|
|
188
|
+
/** Overrides the host name every generated URL advertises. */
|
|
189
|
+
exports.LOCAL_HOST_ENV_VAR = "ORY_LOCAL_HOST";
|
|
190
|
+
/**
|
|
191
|
+
* Skips every port probe — the pre-start preflight *and* the post-failure
|
|
192
|
+
* diagnosis.
|
|
193
|
+
*
|
|
194
|
+
* Both open real sockets, which is the right thing before starting containers
|
|
195
|
+
* and the wrong thing in a unit test (the core suite sets this so no test
|
|
196
|
+
* depends on which ports happen to be free on the machine running it) or in a
|
|
197
|
+
* sandbox that forbids listening. The sandbox case is why this covers the
|
|
198
|
+
* diagnosis too: where binding is denied, `isPortAvailable` answers "taken" for
|
|
199
|
+
* every port, so an unrelated startup failure would otherwise be reported as a
|
|
200
|
+
* confident and completely wrong "every port is in use".
|
|
201
|
+
*/
|
|
202
|
+
exports.SKIP_PORT_CHECK_ENV_VAR = "ORY_LOCAL_SKIP_PORT_CHECK";
|
|
203
|
+
function portCheckDisabled(env = process.env) {
|
|
204
|
+
const raw = env[exports.SKIP_PORT_CHECK_ENV_VAR]?.trim().toLowerCase();
|
|
205
|
+
if (!raw)
|
|
206
|
+
return false;
|
|
207
|
+
return raw !== "0" && raw !== "false" && raw !== "no" && raw !== "off";
|
|
208
|
+
}
|
|
209
|
+
const MIN_PORT = 1;
|
|
210
|
+
const MAX_PORT = 65535;
|
|
211
|
+
function parsePort(raw) {
|
|
212
|
+
// Reject anything that isn't a bare integer — `"4000x"`, `"40.5"`, `" "`.
|
|
213
|
+
// parseInt would happily accept the first two and produce a port the user
|
|
214
|
+
// did not ask for, which is worse than ignoring the value.
|
|
215
|
+
if (!/^\d+$/.test(raw))
|
|
216
|
+
return undefined;
|
|
217
|
+
const value = Number(raw);
|
|
218
|
+
if (!Number.isInteger(value) || value < MIN_PORT || value > MAX_PORT) {
|
|
219
|
+
return undefined;
|
|
220
|
+
}
|
|
221
|
+
return value;
|
|
222
|
+
}
|
|
223
|
+
/**
|
|
224
|
+
* Resolve every host port from the environment.
|
|
225
|
+
*
|
|
226
|
+
* Invalid values are **ignored with a warning** rather than throwing: this runs
|
|
227
|
+
* on the way into `local up`, and refusing to start because one env var has a
|
|
228
|
+
* typo would be a worse outcome than starting on the documented default and
|
|
229
|
+
* saying so. Warnings are returned rather than printed so the caller controls
|
|
230
|
+
* the output stream.
|
|
231
|
+
*/
|
|
232
|
+
function resolveLocalPorts(env = process.env) {
|
|
233
|
+
const warnings = [];
|
|
234
|
+
let offset = 0;
|
|
235
|
+
const rawOffset = env[exports.PORT_OFFSET_ENV_VAR]?.trim();
|
|
236
|
+
if (rawOffset) {
|
|
237
|
+
const parsed = /^-?\d+$/.test(rawOffset) ? Number(rawOffset) : undefined;
|
|
238
|
+
if (parsed === undefined) {
|
|
239
|
+
warnings.push(`${exports.PORT_OFFSET_ENV_VAR}="${rawOffset}" is not an integer — ignoring it and using the default ports.`);
|
|
240
|
+
}
|
|
241
|
+
else {
|
|
242
|
+
offset = parsed;
|
|
243
|
+
}
|
|
244
|
+
}
|
|
245
|
+
const ports = {};
|
|
246
|
+
for (const name of exports.LOCAL_PORT_NAMES) {
|
|
247
|
+
const spec = exports.LOCAL_PORT_SPECS[name];
|
|
248
|
+
const raw = env[spec.envVar]?.trim();
|
|
249
|
+
if (raw) {
|
|
250
|
+
const parsed = parsePort(raw);
|
|
251
|
+
if (parsed === undefined) {
|
|
252
|
+
warnings.push(`${spec.envVar}="${raw}" is not a port between ${MIN_PORT} and ${MAX_PORT} — using ${spec.default} for ${spec.label}.`);
|
|
253
|
+
ports[name] = spec.default;
|
|
254
|
+
}
|
|
255
|
+
else {
|
|
256
|
+
ports[name] = parsed;
|
|
257
|
+
}
|
|
258
|
+
continue;
|
|
259
|
+
}
|
|
260
|
+
if (offset !== 0) {
|
|
261
|
+
const shifted = spec.default + offset;
|
|
262
|
+
if (shifted < MIN_PORT || shifted > MAX_PORT) {
|
|
263
|
+
warnings.push(`${exports.PORT_OFFSET_ENV_VAR}=${offset} puts ${spec.label} at ${shifted}, outside ${MIN_PORT}-${MAX_PORT} — using ${spec.default}. Set ${spec.envVar} to place it explicitly.`);
|
|
264
|
+
ports[name] = spec.default;
|
|
265
|
+
}
|
|
266
|
+
else {
|
|
267
|
+
ports[name] = shifted;
|
|
268
|
+
}
|
|
269
|
+
continue;
|
|
270
|
+
}
|
|
271
|
+
ports[name] = spec.default;
|
|
272
|
+
}
|
|
273
|
+
warnings.push(...describeDuplicatePorts(ports));
|
|
274
|
+
return { ports, warnings };
|
|
275
|
+
}
|
|
276
|
+
/**
|
|
277
|
+
* Two services configured onto the same host port. Only reachable through
|
|
278
|
+
* explicit per-port overrides — the offset preserves the spacing of the
|
|
279
|
+
* defaults — and it would otherwise surface as a confusing Docker error about
|
|
280
|
+
* a port the user *did* mean to claim.
|
|
281
|
+
*/
|
|
282
|
+
function describeDuplicatePorts(ports) {
|
|
283
|
+
const byPort = new Map();
|
|
284
|
+
for (const name of exports.LOCAL_PORT_NAMES) {
|
|
285
|
+
const list = byPort.get(ports[name]) ?? [];
|
|
286
|
+
list.push(name);
|
|
287
|
+
byPort.set(ports[name], list);
|
|
288
|
+
}
|
|
289
|
+
const warnings = [];
|
|
290
|
+
for (const [port, names] of byPort) {
|
|
291
|
+
if (names.length < 2)
|
|
292
|
+
continue;
|
|
293
|
+
const labels = names.map((n) => exports.LOCAL_PORT_SPECS[n].label).join(" and ");
|
|
294
|
+
const vars = names.map((n) => exports.LOCAL_PORT_SPECS[n].envVar).join(" / ");
|
|
295
|
+
warnings.push(`${labels} are both configured on host port ${port} — the stack cannot start. Set ${vars} to different values.`);
|
|
296
|
+
}
|
|
297
|
+
return warnings;
|
|
298
|
+
}
|
|
299
|
+
exports.DEFAULT_LOCAL_HOST = "localhost";
|
|
300
|
+
/**
|
|
301
|
+
* Pull the host out of a `DOCKER_HOST` value.
|
|
302
|
+
*
|
|
303
|
+
* `unix://` and `npipe://` sockets are this machine, so they yield nothing and
|
|
304
|
+
* the default stands. A `tcp://` or `ssh://` daemon publishes the stack's ports
|
|
305
|
+
* on *its* host, not ours, so that host is what generated URLs have to
|
|
306
|
+
* advertise — otherwise every URL we print and persist points at a machine that
|
|
307
|
+
* isn't running the stack.
|
|
308
|
+
*/
|
|
309
|
+
function hostFromDockerHost(dockerHost) {
|
|
310
|
+
const raw = dockerHost?.trim();
|
|
311
|
+
if (!raw)
|
|
312
|
+
return undefined;
|
|
313
|
+
if (raw.startsWith("unix://") || raw.startsWith("npipe://"))
|
|
314
|
+
return undefined;
|
|
315
|
+
let hostname;
|
|
316
|
+
try {
|
|
317
|
+
hostname = new URL(raw).hostname;
|
|
318
|
+
}
|
|
319
|
+
catch {
|
|
320
|
+
return undefined;
|
|
321
|
+
}
|
|
322
|
+
if (!hostname)
|
|
323
|
+
return undefined;
|
|
324
|
+
// A tcp:// daemon on loopback is still this machine — `localhost` reads
|
|
325
|
+
// better in a banner than `127.0.0.1`, and keeps URLs stable for anyone who
|
|
326
|
+
// sets DOCKER_HOST explicitly at the default address.
|
|
327
|
+
if (isLoopbackHost(hostname))
|
|
328
|
+
return undefined;
|
|
329
|
+
return hostname;
|
|
330
|
+
}
|
|
331
|
+
function isLoopbackHost(host) {
|
|
332
|
+
const h = host.toLowerCase().replace(/^\[|\]$/g, "");
|
|
333
|
+
return h === "localhost" || h === "127.0.0.1" || h === "::1";
|
|
334
|
+
}
|
|
335
|
+
/**
|
|
336
|
+
* The host name every generated URL should advertise: config files, banners,
|
|
337
|
+
* the health probe, and the `projectUrl` that `local configure` persists.
|
|
338
|
+
*/
|
|
339
|
+
function resolveLocalHost(env = process.env) {
|
|
340
|
+
const explicit = env[exports.LOCAL_HOST_ENV_VAR]?.trim();
|
|
341
|
+
if (explicit)
|
|
342
|
+
return { host: explicit, source: "env" };
|
|
343
|
+
const fromDocker = hostFromDockerHost(env.DOCKER_HOST);
|
|
344
|
+
if (fromDocker)
|
|
345
|
+
return { host: fromDocker, source: "docker-host" };
|
|
346
|
+
return { host: exports.DEFAULT_LOCAL_HOST, source: "default" };
|
|
347
|
+
}
|
|
348
|
+
/**
|
|
349
|
+
* True when the Docker daemon publishes ports on *this* machine, which is the
|
|
350
|
+
* only case where probing a local socket says anything about whether the stack
|
|
351
|
+
* will be able to bind. With a remote daemon the probe would test the wrong
|
|
352
|
+
* host, so callers skip the preflight entirely rather than report a conflict
|
|
353
|
+
* that isn't there (or miss one that is).
|
|
354
|
+
*/
|
|
355
|
+
function isLocalDockerDaemon(env = process.env) {
|
|
356
|
+
return hostFromDockerHost(env.DOCKER_HOST) === undefined;
|
|
357
|
+
}
|
|
358
|
+
/** Build an `http://host:port` origin, bracketing bare IPv6 literals. */
|
|
359
|
+
function hostUrl(host, port) {
|
|
360
|
+
const needsBrackets = host.includes(":") && !host.startsWith("[");
|
|
361
|
+
return `http://${needsBrackets ? `[${host}]` : host}:${port}`;
|
|
362
|
+
}
|
|
363
|
+
/**
|
|
364
|
+
* Can we bind this port? Docker publishes on all interfaces, so we test the
|
|
365
|
+
* same thing it will do. A port held on loopback alone still fails a
|
|
366
|
+
* wildcard bind, so this catches both.
|
|
367
|
+
*
|
|
368
|
+
* Anything other than a clean listen counts as unavailable: `EADDRINUSE` is the
|
|
369
|
+
* case we are looking for, and `EACCES` (a privileged port without rights)
|
|
370
|
+
* would fail the container just the same.
|
|
371
|
+
*/
|
|
372
|
+
function isPortAvailable(port, timeoutMs = 500) {
|
|
373
|
+
return new Promise((resolve) => {
|
|
374
|
+
const server = net.createServer();
|
|
375
|
+
let settled = false;
|
|
376
|
+
const finish = (available) => {
|
|
377
|
+
if (settled)
|
|
378
|
+
return;
|
|
379
|
+
settled = true;
|
|
380
|
+
clearTimeout(timer);
|
|
381
|
+
server.removeAllListeners();
|
|
382
|
+
try {
|
|
383
|
+
server.close();
|
|
384
|
+
}
|
|
385
|
+
catch {
|
|
386
|
+
/* already closed */
|
|
387
|
+
}
|
|
388
|
+
resolve(available);
|
|
389
|
+
};
|
|
390
|
+
const timer = setTimeout(() => finish(true), timeoutMs);
|
|
391
|
+
timer.unref?.();
|
|
392
|
+
server.once("error", () => finish(false));
|
|
393
|
+
server.once("listening", () => finish(true));
|
|
394
|
+
try {
|
|
395
|
+
server.listen({ port, host: "0.0.0.0", exclusive: true });
|
|
396
|
+
}
|
|
397
|
+
catch {
|
|
398
|
+
finish(false);
|
|
399
|
+
}
|
|
400
|
+
});
|
|
401
|
+
}
|
|
402
|
+
/**
|
|
403
|
+
* Which of the stack's host ports are already taken. Probed concurrently —
|
|
404
|
+
* twelve sequential binds would add noticeable latency to every `local up`.
|
|
405
|
+
*/
|
|
406
|
+
async function findPortConflicts(ports) {
|
|
407
|
+
const checks = exports.LOCAL_PORT_NAMES.map(async (name) => {
|
|
408
|
+
const available = await isPortAvailable(ports[name]);
|
|
409
|
+
return available
|
|
410
|
+
? undefined
|
|
411
|
+
: {
|
|
412
|
+
name,
|
|
413
|
+
port: ports[name],
|
|
414
|
+
label: exports.LOCAL_PORT_SPECS[name].label,
|
|
415
|
+
envVar: exports.LOCAL_PORT_SPECS[name].envVar,
|
|
416
|
+
};
|
|
417
|
+
});
|
|
418
|
+
return (await Promise.all(checks)).filter((c) => c !== undefined);
|
|
419
|
+
}
|
|
420
|
+
/**
|
|
421
|
+
* The message a user gets instead of Docker's "port is already allocated":
|
|
422
|
+
* which service wanted which port, and the two ways to move it.
|
|
423
|
+
*/
|
|
424
|
+
function describePortConflicts(conflicts) {
|
|
425
|
+
if (conflicts.length === 0)
|
|
426
|
+
return "";
|
|
427
|
+
const lines = [
|
|
428
|
+
conflicts.length === 1
|
|
429
|
+
? "Port already in use — the local Ory stack cannot start:"
|
|
430
|
+
: `${conflicts.length} ports already in use — the local Ory stack cannot start:`,
|
|
431
|
+
"",
|
|
432
|
+
...conflicts.map((c) => ` ${c.port} ${c.label} (override with ${c.envVar})`),
|
|
433
|
+
"",
|
|
434
|
+
"The defaults are the stock Ory ports, so another Ory instance is the usual cause.",
|
|
435
|
+
"Move the whole stack out of the way with a single offset:",
|
|
436
|
+
"",
|
|
437
|
+
` ${exports.PORT_OFFSET_ENV_VAR}=100 <command>`,
|
|
438
|
+
"",
|
|
439
|
+
"or pin individual services with the variables listed above. Do not edit the",
|
|
440
|
+
"generated compose file — the next 'local up' regenerates it.",
|
|
441
|
+
];
|
|
442
|
+
return lines.join("\n");
|
|
443
|
+
}
|
package/dist/local/seed.d.ts
CHANGED
|
@@ -22,12 +22,16 @@
|
|
|
22
22
|
* recreates OAuth2 clients (so the secret is always known).
|
|
23
23
|
*/
|
|
24
24
|
/**
|
|
25
|
-
*
|
|
26
|
-
*
|
|
27
|
-
*
|
|
25
|
+
* The client id Hydra issues to the seeded user PKCE client: the same
|
|
26
|
+
* **reserved** id Ory Network's Agent Security setup uses, so local dev and a
|
|
27
|
+
* hosted project name the shared login client identically and the id — never a
|
|
28
|
+
* `client_name` — is what resolves it in both.
|
|
29
|
+
*
|
|
30
|
+
* Stable, so `local configure` can persist it to the shared config and
|
|
31
|
+
* downstream runs can rely on `ORY_OAUTH2_CLIENT_ID` resolution without first
|
|
28
32
|
* dragging the value out of the `local up` banner.
|
|
29
33
|
*/
|
|
30
|
-
export declare const USER_CLIENT_ID = "ory-
|
|
34
|
+
export declare const USER_CLIENT_ID = "ory-agent-security-login";
|
|
31
35
|
export interface SeededIdentity {
|
|
32
36
|
id: string;
|
|
33
37
|
email: string;
|
|
@@ -56,7 +60,11 @@ export interface SeedResult {
|
|
|
56
60
|
tuples: number;
|
|
57
61
|
};
|
|
58
62
|
}
|
|
59
|
-
/**
|
|
63
|
+
/**
|
|
64
|
+
* Subject namespace for user identities in seeded permission tuples. Re-exported
|
|
65
|
+
* from the core default so the seed, the runtime resolver, and the persisted
|
|
66
|
+
* install config all address the user under the same namespace.
|
|
67
|
+
*/
|
|
60
68
|
export declare const USER_SUBJECT_NAMESPACE = "User";
|
|
61
69
|
/**
|
|
62
70
|
* Run the full seed process. Idempotent — safe to run multiple times.
|
package/dist/local/seed.js
CHANGED
|
@@ -26,26 +26,32 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
26
26
|
exports.USER_SUBJECT_NAMESPACE = exports.USER_CLIENT_ID = void 0;
|
|
27
27
|
exports.seedLocalEnvironment = seedLocalEnvironment;
|
|
28
28
|
const auth_js_1 = require("../auth.js");
|
|
29
|
+
const branding_js_1 = require("../branding.js");
|
|
29
30
|
const tool_catalog_js_1 = require("../tool-catalog.js");
|
|
31
|
+
const subject_js_1 = require("../subject.js");
|
|
32
|
+
const opl_js_1 = require("../opl.js");
|
|
30
33
|
const configs_js_1 = require("./configs.js");
|
|
34
|
+
const ports_js_1 = require("./ports.js");
|
|
31
35
|
const health_js_1 = require("./health.js");
|
|
32
|
-
const KRATOS_ADMIN =
|
|
33
|
-
const KETO_WRITE =
|
|
34
|
-
const HYDRA_ADMIN =
|
|
36
|
+
const KRATOS_ADMIN = (0, ports_js_1.hostUrl)(configs_js_1.LOCAL_STACK_HOST, configs_js_1.KRATOS_ADMIN_PORT);
|
|
37
|
+
const KETO_WRITE = (0, ports_js_1.hostUrl)(configs_js_1.LOCAL_STACK_HOST, configs_js_1.KETO_WRITE_PORT);
|
|
38
|
+
const HYDRA_ADMIN = (0, ports_js_1.hostUrl)(configs_js_1.LOCAL_STACK_HOST, configs_js_1.HYDRA_ADMIN_PORT);
|
|
35
39
|
const USER_EMAIL = "user@ory-local.dev";
|
|
36
40
|
const USER_PASSWORD = "ory-user-local-dev-password!";
|
|
37
|
-
const USER_CLIENT_NAME = "ory-agent-plugins-local-user";
|
|
38
41
|
/**
|
|
39
|
-
*
|
|
40
|
-
*
|
|
41
|
-
*
|
|
42
|
+
* The client id Hydra issues to the seeded user PKCE client: the same
|
|
43
|
+
* **reserved** id Ory Network's Agent Security setup uses, so local dev and a
|
|
44
|
+
* hosted project name the shared login client identically and the id — never a
|
|
45
|
+
* `client_name` — is what resolves it in both.
|
|
46
|
+
*
|
|
47
|
+
* Stable, so `local configure` can persist it to the shared config and
|
|
48
|
+
* downstream runs can rely on `ORY_OAUTH2_CLIENT_ID` resolution without first
|
|
42
49
|
* dragging the value out of the `local up` banner.
|
|
43
50
|
*/
|
|
44
|
-
exports.USER_CLIENT_ID =
|
|
51
|
+
exports.USER_CLIENT_ID = branding_js_1.USER_LOGIN_CLIENT_ID;
|
|
45
52
|
/**
|
|
46
|
-
* Tools the
|
|
47
|
-
*
|
|
48
|
-
* `use` on every harness's built-in tool set.
|
|
53
|
+
* Tools the explicit local-stack command seeds tuples for. Sourced from the
|
|
54
|
+
* shared catalog so one seed covers every harness's built-in tool set.
|
|
49
55
|
*/
|
|
50
56
|
const COMMON_TOOLS = tool_catalog_js_1.ALL_TOOLS;
|
|
51
57
|
async function jsonFetch(url, opts = {}) {
|
|
@@ -82,8 +88,12 @@ async function seedIdentity(email, password, name) {
|
|
|
82
88
|
}));
|
|
83
89
|
return { id: identity.id, email };
|
|
84
90
|
}
|
|
85
|
-
/**
|
|
86
|
-
|
|
91
|
+
/**
|
|
92
|
+
* Subject namespace for user identities in seeded permission tuples. Re-exported
|
|
93
|
+
* from the core default so the seed, the runtime resolver, and the persisted
|
|
94
|
+
* install config all address the user under the same namespace.
|
|
95
|
+
*/
|
|
96
|
+
exports.USER_SUBJECT_NAMESPACE = subject_js_1.DEFAULT_USER_SUBJECT_NAMESPACE;
|
|
87
97
|
/**
|
|
88
98
|
* Write permission tuples granting the user identity access to all
|
|
89
99
|
* common tools. The subject is written as a SubjectSet
|
|
@@ -91,16 +101,16 @@ exports.USER_SUBJECT_NAMESPACE = "User";
|
|
|
91
101
|
* dialog — which only emits SubjectSet subjects — can recreate the same
|
|
92
102
|
* tuple by hand during the runbook walkthrough.
|
|
93
103
|
*/
|
|
94
|
-
async function seedPermissions(userId, namespace) {
|
|
104
|
+
async function seedPermissions(userId, namespace, objects = COMMON_TOOLS) {
|
|
95
105
|
let created = 0;
|
|
96
|
-
for (const
|
|
106
|
+
for (const object of objects) {
|
|
97
107
|
try {
|
|
98
108
|
await jsonFetch(`${KETO_WRITE}/admin/relation-tuples`, {
|
|
99
109
|
method: "PUT",
|
|
100
110
|
body: JSON.stringify({
|
|
101
111
|
namespace,
|
|
102
|
-
object
|
|
103
|
-
relation:
|
|
112
|
+
object,
|
|
113
|
+
relation: opl_js_1.RELATION_USERS,
|
|
104
114
|
subject_set: {
|
|
105
115
|
namespace: exports.USER_SUBJECT_NAMESPACE,
|
|
106
116
|
object: userId,
|
|
@@ -113,7 +123,7 @@ async function seedPermissions(userId, namespace) {
|
|
|
113
123
|
catch (err) {
|
|
114
124
|
const msg = err instanceof Error ? err.message : String(err);
|
|
115
125
|
if (!msg.includes("409")) {
|
|
116
|
-
process.stderr.write(` Warning: failed to create permission for ${
|
|
126
|
+
process.stderr.write(` Warning: failed to create permission for ${object}: ${msg}\n`);
|
|
117
127
|
}
|
|
118
128
|
else {
|
|
119
129
|
created++;
|
|
@@ -123,25 +133,29 @@ async function seedPermissions(userId, namespace) {
|
|
|
123
133
|
return created;
|
|
124
134
|
}
|
|
125
135
|
/**
|
|
126
|
-
* Delete a Hydra OAuth2 client if it exists, then create it
|
|
127
|
-
* known
|
|
128
|
-
* exact credentials to inject into the
|
|
136
|
+
* Delete a Hydra OAuth2 client if it exists, then create it at a known
|
|
137
|
+
* client_id (with a known secret, for a confidential client). We always
|
|
138
|
+
* recreate so the launcher knows the exact credentials to inject into the
|
|
139
|
+
* harness env.
|
|
140
|
+
*
|
|
141
|
+
* The client is addressed **by id**, never by `client_name`. That mirrors how
|
|
142
|
+
* Ory Network resolves the shared login client — the name is a display label
|
|
143
|
+
* anyone can register a client under, so only the reserved id identifies it
|
|
144
|
+
* (see `USER_LOGIN_CLIENT_ID`) — so local dev cannot pass with a lookup shape
|
|
145
|
+
* that would be unsafe against a hosted project.
|
|
129
146
|
*/
|
|
130
147
|
async function ensureOAuth2Client(spec) {
|
|
131
|
-
//
|
|
132
|
-
//
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
catch {
|
|
143
|
-
// best-effort cleanup
|
|
144
|
-
}
|
|
148
|
+
// Delete the client at this id if one is already there, so the recreate
|
|
149
|
+
// below lands with the exact grants, scopes, and redirect URIs this seed
|
|
150
|
+
// declares. A 404 (nothing to delete) is the normal first-run case.
|
|
151
|
+
try {
|
|
152
|
+
await jsonFetch(`${HYDRA_ADMIN}/admin/clients/${encodeURIComponent(spec.clientId)}`, {
|
|
153
|
+
method: "DELETE",
|
|
154
|
+
});
|
|
155
|
+
}
|
|
156
|
+
catch {
|
|
157
|
+
// best-effort cleanup — absent, or Hydra refused; the create below reports
|
|
158
|
+
// the real problem if there is one.
|
|
145
159
|
}
|
|
146
160
|
const body = {
|
|
147
161
|
client_id: spec.clientId,
|
|
@@ -174,7 +188,7 @@ function loopbackRedirectUris() {
|
|
|
174
188
|
* Returns a `SeedResult` describing both identities, the user's
|
|
175
189
|
* pre-minted session, and the OAuth2 clients registered for each.
|
|
176
190
|
*/
|
|
177
|
-
async function seedLocalEnvironment(namespace = "
|
|
191
|
+
async function seedLocalEnvironment(namespace = "AgentTool") {
|
|
178
192
|
process.stderr.write("Seeding local Ory environment...\n\n");
|
|
179
193
|
// 0. Readiness barrier. The seed writes directly to Kratos (admin),
|
|
180
194
|
// Keto (write), and Hydra (admin). Neither the static nginx gateway
|
|
@@ -203,6 +217,14 @@ async function seedLocalEnvironment(namespace = "AgentTools") {
|
|
|
203
217
|
process.stderr.write(` Creating permissions for ${COMMON_TOOLS.length} tools...\n`);
|
|
204
218
|
const tupleCount = await seedPermissions(userIdentity.id, namespace);
|
|
205
219
|
process.stderr.write(` Permissions: ${tupleCount} entries in '${namespace}' for ${subjectLabel}\n`);
|
|
220
|
+
// Shell-command sub-tools (issue #76): grant every catalog word in the
|
|
221
|
+
// ShellTool namespace so a launched harness can run `bash -c "curl …"`
|
|
222
|
+
// out of the box, and the enforce demo (revoke `ShellTool:curl#users`,
|
|
223
|
+
// watch it block) works without hand-writing tuples first.
|
|
224
|
+
const shellWords = (0, tool_catalog_js_1.getShellCommandCatalog)();
|
|
225
|
+
const shellNamespace = (0, tool_catalog_js_1.resolveShellCommandNamespace)();
|
|
226
|
+
const shellCount = await seedPermissions(userIdentity.id, shellNamespace, shellWords);
|
|
227
|
+
process.stderr.write(` Shell commands: ${shellCount} entries in '${shellNamespace}' for ${subjectLabel}\n`);
|
|
206
228
|
// 3. User OAuth2 client (PKCE) — pre-registered so the user gate's
|
|
207
229
|
// PKCE flow has somewhere to authenticate against. The agent's
|
|
208
230
|
// OAuth2 client is intentionally NOT pre-registered; the harness
|
|
@@ -211,13 +233,15 @@ async function seedLocalEnvironment(namespace = "AgentTools") {
|
|
|
211
233
|
let userClient = { clientId: exports.USER_CLIENT_ID };
|
|
212
234
|
try {
|
|
213
235
|
userClient = await ensureOAuth2Client({
|
|
214
|
-
|
|
236
|
+
// Display label only, matching what a hosted project shows in the
|
|
237
|
+
// Console — the client is addressed by its id.
|
|
238
|
+
clientName: branding_js_1.USER_LOGIN_CLIENT_NAME,
|
|
215
239
|
clientId: exports.USER_CLIENT_ID,
|
|
216
240
|
// Public PKCE client — no secret. Hydra accepts an empty string
|
|
217
241
|
// for `token_endpoint_auth_method=none`.
|
|
218
242
|
grantTypes: ["authorization_code", "refresh_token"],
|
|
219
243
|
responseTypes: ["code"],
|
|
220
|
-
scope:
|
|
244
|
+
scope: branding_js_1.USER_LOGIN_SCOPE_OAUTH,
|
|
221
245
|
tokenEndpointAuthMethod: "none",
|
|
222
246
|
redirectUris: loopbackRedirectUris(),
|
|
223
247
|
});
|