Skip to content
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
42 changes: 33 additions & 9 deletions docs/libraries/lib-context.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,8 @@ Returns

*object* : (<<Context,`Context`>>) The current context. The `attributes` field is always present (possibly empty); `branch`, `repository`, and `authInfo` are present when set on the calling context.

In TypeScript, `get()` takes an optional type argument naming the attributes you expect to read. Each is typed as optional, since nothing guarantees it was set. Any other attribute stays readable as a plain `ContextAttributeValue`.

[.lead]
Example

Expand All @@ -44,6 +46,16 @@ import {get} from '/lib/xp/context';
const context = get();
----

.Typing the attributes you read
[source,typescript]
----
import {get} from '/lib/xp/context';

type MyData = {values: string[]};

const data = get<{'custom.my-data': MyData}>().attributes['custom.my-data']; // MyData | undefined
----

.Sample response
[source,typescript]
----
Expand Down Expand Up @@ -138,6 +150,8 @@ Parameters

Takes two positional arguments: `name` (string) — the attribute name, stored with the `custom.` prefix — and `value`, the JSON-like value to store. Passing `null`, `undefined`, or omitting the value removes the attribute.

In TypeScript, a type argument names the type of the value: `+setCustomLocalAttribute<MyData>('my-data', value)+` accepts only a `MyData` whose fields are all JSON-like, so a function or `Date` anywhere in it is a compile error as well as a runtime one. The type argument itself is a compile-time aid: the runtime rejects non-JSON values as described above, but does not check the value against `MyData`. Use the same type on the read side with <<get, `get()`>>.

[.lead]
Returns

Expand All @@ -151,33 +165,41 @@ Example
----
import {get, setCustomLocalAttribute} from '/lib/xp/context';

setCustomLocalAttribute('my-data', {values: ['one', 'two']});
type MyData = {values: string[]};

setCustomLocalAttribute<MyData>('my-data', {values: ['one', 'two']});

const data = get().attributes['custom.my-data'];
const data = get<{'custom.my-data': MyData}>().attributes['custom.my-data'];
----

.Hand data from a page implementation to a response processor
[source,typescript]
----
// cms/pages/article/article.ts
import {setCustomLocalAttribute} from '/lib/xp/context';
import type {Tracking} from '/lib/tracking';

export function GET() {
setCustomLocalAttribute('com.example.myapp.tracking', {pageType: 'article', experiment: 'B'});
setCustomLocalAttribute<Tracking>('com.example.myapp.tracking', {pageType: 'article', experiment: 'B'});

return {body: renderArticle(), contentType: 'text/html'};
}
----

[source,typescript]
----
// lib/tracking.ts
export type Tracking = {pageType: string; experiment: string};
----

[source,typescript]
----
// cms/processors/tracker.ts
import {get as getContext} from '/lib/xp/context';

type Tracking = {pageType: string; experiment: string};
import type {Tracking} from '/lib/tracking';

export function responseProcessor(req, res) {
const tracking = getContext().attributes['custom.com.example.myapp.tracking'] as Tracking | undefined;
const tracking = getContext<{'custom.com.example.myapp.tracking': Tracking}>().attributes['custom.com.example.myapp.tracking'];

if (tracking) {
res.pageContributions.bodyEnd = [
Expand All @@ -196,7 +218,7 @@ NOTE: A value stored during a request is *not* carried into a task submitted fro
[#Context]
=== Context

The shape of the object returned by `get()`.
The shape of the object returned by `get()`. In TypeScript it takes an optional type argument, `+Context<Attributes>+`, whose properties are added to `attributes` as optional, typed entries.

[.lead]
Properties
Expand All @@ -206,7 +228,7 @@ Properties
[grid="none"]
|===
| Name | Type | Description
| attributes | <<ContextAttributes, ContextAttributes>> | Custom attributes set on the context. Always present; may be empty. Attributes stored with <<setcustomlocalattribute, `setCustomLocalAttribute()`>> appear here under their `custom.` prefixed name.
| attributes | <<ContextAttributes, ContextAttributes>> | Custom attributes set on the context. Always present; may be empty. Attributes stored with <<setcustomlocalattribute, `setCustomLocalAttribute()`>> appear here under their `custom.` prefixed name, typed by the type argument when one is given.
| branch | string | *Optional.* Branch context.
| repository | string | *Optional.* Repository context.
| authInfo | <<AuthInfo, AuthInfo>> | *Optional.* Authentication information for the current context.
Expand Down Expand Up @@ -271,7 +293,9 @@ Properties

Attributes are read and written through different value sets, so the two directions do not share a type.

*Reading* — `<<Context, Context>>.attributes` — is a record of JSON-like values: strings, numbers, booleans, arrays, and objects nesting those. Everything stored with <<setcustomlocalattribute, `setCustomLocalAttribute()`>> comes back in full, keyed as `+custom.<name>+`. In TypeScript the value type is `ContextAttributeValue`.
*Reading* — `<<Context, Context>>.attributes` — is a record of JSON-like values: strings, numbers, booleans, arrays, and objects nesting those. Everything stored with <<setcustomlocalattribute, `setCustomLocalAttribute()`>> comes back in full, keyed as `+custom.<name>+`. In TypeScript the value type is `ContextAttributeValue`, or the type named in the type argument to `get()`.

*Storing* — `setCustomLocalAttribute()` — takes a `+CustomAttributeValue<T>+`: the JSON-like shape of `T`, where functions and non-JSON objects such as `Date` become `never`, so they fail to compile just as they fail at runtime. Without a type argument it is the same as `ContextAttributeValue`.

*Writing* — `<<ContextParams, ContextParams>>.attributes`, passed to `run()` — takes `number`, `string` and `boolean`. An object value is accepted and is visible to Java code reading the context, but it is not part of what `get()` returns.

Expand Down
Loading