@segmentstream-cloud/app 0.17.0 → 0.17.2
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 +39 -8
- package/dist/agent.d.ts +2 -1
- package/dist/agent.js +1 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.js +1 -0
- package/dist/request-timing.d.ts +6 -0
- package/dist/request-timing.js +53 -0
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -347,16 +347,19 @@ export const { POST } = segmentstream.agent.connectHandler();
|
|
|
347
347
|
|
|
348
348
|
`segmentstream.agent` holds:
|
|
349
349
|
|
|
350
|
-
| Call | Does
|
|
351
|
-
| ---------------------- |
|
|
352
|
-
| `pairing(code)` | `{ provider, display, expiresAt }`; throws `not_found` or `expired`
|
|
353
|
-
| `approvePairing(code)` | Links the account to the signed-in member; returns the `AgentIdentity`
|
|
354
|
-
| `identities()` | The member's own: `{ id, provider, externalId, display, createdAt, revokedAt }`
|
|
355
|
-
| `revokeIdentity(id)` | Revokes one of them at once
|
|
356
|
-
| `connectHandler()` | `{ POST }` for the page's form: same-origin only
|
|
350
|
+
| Call | Does |
|
|
351
|
+
| ---------------------- | -------------------------------------------------------------------------------------- |
|
|
352
|
+
| `pairing(code)` | `{ provider, display, expiresAt }`; throws `not_found` or `expired` |
|
|
353
|
+
| `approvePairing(code)` | Links the account to the signed-in member; returns the `AgentIdentity` |
|
|
354
|
+
| `identities()` | The member's own: `{ id, provider, externalId, display, createdAt, revokedAt }` |
|
|
355
|
+
| `revokeIdentity(id)` | Revokes one of them at once |
|
|
356
|
+
| `connectHandler()` | `{ POST }` for the page's form: same-origin only; `303` on success; throws on conflict |
|
|
357
357
|
|
|
358
358
|
The handler sends the browser back to `/agent/connect?connected=<provider>`, or to
|
|
359
|
-
`/agent/connect?expired=1` when the code was used or is older than ten minutes.
|
|
359
|
+
`/agent/connect?expired=1` when the code was used or is older than ten minutes. An account already
|
|
360
|
+
connected to another member throws `SegmentStreamApiError` with status `409` and
|
|
361
|
+
`code === "identity_in_use"` through the app's existing error mechanism. The app owns conflict copy.
|
|
362
|
+
Same-member pairing is idempotent, and replacing your own previous account on a provider is supported. Other
|
|
360
363
|
refusals, such as `forbidden` for a member the ontology does not admit, throw
|
|
361
364
|
`SegmentStreamApiError`. All calls are server-only and run as the signed-in member;
|
|
362
365
|
the ontology decides every one. The workspace starter renders the page with Tailwind CSS
|
|
@@ -698,6 +701,34 @@ Replace segmentstream.semantic with typed warehouse-backed entity aggregates. Se
|
|
|
698
701
|
deployed with `@segmentstream-cloud/ontology` 0.17.0 or later. Requests that use none of
|
|
699
702
|
them work as before.
|
|
700
703
|
|
|
704
|
+
## Request timing
|
|
705
|
+
|
|
706
|
+
Wrap app Route Handlers to add `Server-Timing: app;dur=…`, `x-request-id` and safe
|
|
707
|
+
structured `app.request` runtime logs:
|
|
708
|
+
|
|
709
|
+
```ts
|
|
710
|
+
import { withRequestTiming } from "@segmentstream-cloud/app";
|
|
711
|
+
|
|
712
|
+
export const GET = withRequestTiming(async (request: Request) => {
|
|
713
|
+
return Response.json({ ok: true });
|
|
714
|
+
});
|
|
715
|
+
```
|
|
716
|
+
|
|
717
|
+
The wrapper passes handler arguments through and preserves response headers and
|
|
718
|
+
streaming bodies. It logs duration, method, HTTP status and a generated request ID,
|
|
719
|
+
excluding URLs, cookies, bodies and error details. Errors propagate unchanged.
|
|
720
|
+
Next.js redirects and `notFound()` log their HTTP status and propagate unchanged;
|
|
721
|
+
other Next.js control-flow exceptions log `status: null` because Next owns their eventual response.
|
|
722
|
+
Those exceptions cannot receive timing headers here;
|
|
723
|
+
return an explicit response when the wrapper needs to decorate its headers.
|
|
724
|
+
Read these logs with `segmentstream logs --service app` (deployment permission required).
|
|
725
|
+
Duration ends when the handler returns response headers; it excludes later stream
|
|
726
|
+
work and browser rendering. It is opt-in for Route Handlers, not a page renderer
|
|
727
|
+
or a web vitals collector. A Next.js proxy cannot time the downstream page render.
|
|
728
|
+
|
|
729
|
+
Ontology SDK 0.31.2 adds request timing for ontology calls automatically. Timings
|
|
730
|
+
are available in hosted logs; retained diagnostics are tracked in issue #520.
|
|
731
|
+
|
|
701
732
|
## Upgrading to 0.14
|
|
702
733
|
|
|
703
734
|
- `segmentstream.ontology.aggregate()` accepts the measures of the model by their bare names, typed
|
package/dist/agent.d.ts
CHANGED
|
@@ -34,7 +34,8 @@ export interface AgentIdentities {
|
|
|
34
34
|
readonly pairing: (code: string) => Promise<AgentPairing>;
|
|
35
35
|
/**
|
|
36
36
|
* Links the pairing's chat account to the signed-in member. The ontology decides: it refuses a
|
|
37
|
-
* used or expired code (`not_found`, `expired`)
|
|
37
|
+
* used or expired code (`not_found`, `expired`), a member it does not admit (`forbidden`), or an
|
|
38
|
+
* account linked to another member (`identity_in_use`, HTTP 409).
|
|
38
39
|
* Server-only.
|
|
39
40
|
*/
|
|
40
41
|
readonly approvePairing: (code: string) => Promise<AgentIdentity>;
|
package/dist/agent.js
CHANGED
package/dist/index.d.ts
CHANGED
|
@@ -18,6 +18,7 @@ export declare function createSegmentStreamApp<O = unknown>(config: SegmentStrea
|
|
|
18
18
|
export { NOT_INVITED, SIGN_IN_LINK_INVALID, SegmentStreamApiError } from "./errors.js";
|
|
19
19
|
export { grants, isAllowed } from "./permissions.js";
|
|
20
20
|
export { sql } from "./parameters.js";
|
|
21
|
+
export { withRequestTiming } from "./request-timing.js";
|
|
21
22
|
export type { AuthenticationMethod, SegmentStreamApp } from "./app.js";
|
|
22
23
|
export { CONSENT_PAGE } from "./oauth.js";
|
|
23
24
|
export { AGENT_CONNECT_HANDLER, AGENT_CONNECT_PAGE } from "./agent.js";
|
package/dist/index.js
CHANGED
|
@@ -19,6 +19,7 @@ export function createSegmentStreamApp(config) {
|
|
|
19
19
|
export { NOT_INVITED, SIGN_IN_LINK_INVALID, SegmentStreamApiError } from "./errors.js";
|
|
20
20
|
export { grants, isAllowed } from "./permissions.js";
|
|
21
21
|
export { sql } from "./parameters.js";
|
|
22
|
+
export { withRequestTiming } from "./request-timing.js";
|
|
22
23
|
export { CONSENT_PAGE } from "./oauth.js";
|
|
23
24
|
export { AGENT_CONNECT_HANDLER, AGENT_CONNECT_PAGE } from "./agent.js";
|
|
24
25
|
export { createBlobStorageClient, } from "./storage.js";
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Time an app Route Handler until it returns response headers. Streaming/rendering after that
|
|
3
|
+
* point is excluded. Logs contain no URL, cookies, body or error text. Server Components need
|
|
4
|
+
* framework instrumentation for complete page timing; a Next.js proxy only times authentication.
|
|
5
|
+
*/
|
|
6
|
+
export declare function withRequestTiming<R extends Request, A extends unknown[]>(handler: (request: R, ...args: A) => Promise<Response>): (request: R, ...args: A) => Promise<Response>;
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
import { unstable_rethrow } from "next/navigation";
|
|
2
|
+
import { getRedirectStatusCodeFromError } from "next/dist/client/components/redirect.js";
|
|
3
|
+
import { isRedirectError } from "next/dist/client/components/redirect-error.js";
|
|
4
|
+
import { getAccessFallbackHTTPStatus, isHTTPAccessFallbackError, } from "next/dist/client/components/http-access-fallback/http-access-fallback.js";
|
|
5
|
+
/**
|
|
6
|
+
* Time an app Route Handler until it returns response headers. Streaming/rendering after that
|
|
7
|
+
* point is excluded. Logs contain no URL, cookies, body or error text. Server Components need
|
|
8
|
+
* framework instrumentation for complete page timing; a Next.js proxy only times authentication.
|
|
9
|
+
*/
|
|
10
|
+
export function withRequestTiming(handler) {
|
|
11
|
+
return async (request, ...args) => {
|
|
12
|
+
const started = performance.now();
|
|
13
|
+
const requestId = crypto.randomUUID();
|
|
14
|
+
let status = 500;
|
|
15
|
+
let durationMs;
|
|
16
|
+
try {
|
|
17
|
+
const response = await handler(request, ...args);
|
|
18
|
+
const headers = new Headers(response.headers);
|
|
19
|
+
durationMs = Math.round((performance.now() - started) * 100) / 100;
|
|
20
|
+
status = response.status;
|
|
21
|
+
headers.append("server-timing", `app;dur=${durationMs}`);
|
|
22
|
+
headers.set("x-request-id", requestId);
|
|
23
|
+
return new Response(response.body, {
|
|
24
|
+
status,
|
|
25
|
+
statusText: response.statusText,
|
|
26
|
+
headers,
|
|
27
|
+
});
|
|
28
|
+
}
|
|
29
|
+
catch (error) {
|
|
30
|
+
try {
|
|
31
|
+
unstable_rethrow(error);
|
|
32
|
+
}
|
|
33
|
+
catch {
|
|
34
|
+
// Next owns the eventual response for control-flow exceptions, outside this wrapper.
|
|
35
|
+
status = isRedirectError(error)
|
|
36
|
+
? getRedirectStatusCodeFromError(error)
|
|
37
|
+
: isHTTPAccessFallbackError(error)
|
|
38
|
+
? getAccessFallbackHTTPStatus(error)
|
|
39
|
+
: null;
|
|
40
|
+
}
|
|
41
|
+
throw error;
|
|
42
|
+
}
|
|
43
|
+
finally {
|
|
44
|
+
console.info(JSON.stringify({
|
|
45
|
+
event: "app.request",
|
|
46
|
+
requestId,
|
|
47
|
+
method: request.method,
|
|
48
|
+
status,
|
|
49
|
+
durationMs: durationMs ?? Math.round((performance.now() - started) * 100) / 100,
|
|
50
|
+
}));
|
|
51
|
+
}
|
|
52
|
+
};
|
|
53
|
+
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@segmentstream-cloud/app",
|
|
3
|
-
"version": "0.17.
|
|
3
|
+
"version": "0.17.2",
|
|
4
4
|
"description": "Sign-in, users, permissions, the ontology client and warehouse data access for SegmentStream workspace apps built with Next.js.",
|
|
5
5
|
"license": "Apache-2.0",
|
|
6
6
|
"author": "SegmentStream",
|