@foir/sdk 0.8.0 → 0.9.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/CHANGELOG.md +54 -2
- package/dist/auth/hosted.d.ts +22 -0
- package/dist/auth/index.d.ts +1 -1
- package/dist/auth.js +11 -0
- package/dist/data/builtins.d.ts +67 -0
- package/dist/data/index.d.ts +2 -2
- package/dist/data/manifest.d.ts +24 -5
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -104,8 +104,60 @@ on `dev` would publish unreviewed work to npm.
|
|
|
104
104
|
|
|
105
105
|
Changes on `dev` that have not been published to npm.
|
|
106
106
|
|
|
107
|
-
|
|
108
|
-
|
|
107
|
+
---
|
|
108
|
+
|
|
109
|
+
## [0.9.0] — 2026-08-20
|
|
110
|
+
|
|
111
|
+
Everything additive, so a MINOR either way under the pre-1.0 note.
|
|
112
|
+
|
|
113
|
+
### Added
|
|
114
|
+
|
|
115
|
+
- **`hostedLogoutUrl(config, clientId, returnTo?)` on `./auth`** — the mirror of
|
|
116
|
+
`hostedLoginUrl`, and the only thing that actually signs a customer out on the
|
|
117
|
+
hosted-cookie flow.
|
|
118
|
+
|
|
119
|
+
Login on that flow is symmetric across browser and server; logout was not.
|
|
120
|
+
The apex `foir_customer_session` cookie is the durable credential, and
|
|
121
|
+
disposing of a bearer, clearing a local session, or calling the
|
|
122
|
+
`customerLogout` mutation all leave it in place — the next request
|
|
123
|
+
re-establishes the customer from it. The only surface that ended a session was
|
|
124
|
+
`POST /session/logout`, cookie-authenticated and CSRF-header-gated, which only
|
|
125
|
+
a browser sending `credentials: 'include'` can reach.
|
|
126
|
+
|
|
127
|
+
This is a URL builder: no transport, no CORS surface, no CSRF header, no
|
|
128
|
+
JavaScript required. Server-side logout becomes
|
|
129
|
+
`return redirect(hostedLogoutUrl(config, clientId, returnTo))`. `returnTo`
|
|
130
|
+
must be absolute and on an origin registered for `clientId`.
|
|
131
|
+
|
|
132
|
+
Requires the platform's `end-session` endpoint (TTS-1534). `HostedLoginConfig`
|
|
133
|
+
gains an optional `endSessionPath`, defaulting to `/session/end-session`.
|
|
134
|
+
|
|
135
|
+
- **`Prose`, `Passage`, `ProseSpan` and `RecordAncestor` on `./data`.** The
|
|
136
|
+
shapes a prose field and the record hierarchy resolve to, shipped here
|
|
137
|
+
rather than generated per project because they are identical everywhere —
|
|
138
|
+
the same reason `Image` and `Reference` live here.
|
|
139
|
+
|
|
140
|
+
`Prose<E>` is parameterised on its entries element: `Prose<Passage>` for a
|
|
141
|
+
text-only field, `Prose<Cta | Passage>` for one that admits embeds. `foir
|
|
142
|
+
types` fills the parameter in from the field's own member set.
|
|
143
|
+
|
|
144
|
+
- **`FoirManifestStructural`, and `structurals` on `FoirManifestModel`.** The
|
|
145
|
+
manifest's bucket for a platform-owned object with no model behind it — a
|
|
146
|
+
prose wrapper, an `ancestors` list. Absent on a server that predates it,
|
|
147
|
+
where those fields landed in `unclassifiedFields` and dropped out of the
|
|
148
|
+
selection entirely; widen on absent.
|
|
149
|
+
|
|
150
|
+
---
|
|
151
|
+
|
|
152
|
+
## [0.8.0] — 2026-08-20
|
|
153
|
+
|
|
154
|
+
**BREAKING** — see `foir.raw()` under "Changed". A MINOR, per the pre-1.0
|
|
155
|
+
note above.
|
|
156
|
+
|
|
157
|
+
> Filed after the fact. 0.8.0 was published with a version bump and no
|
|
158
|
+
> changelog entry, so everything below sat under "Unreleased" while it was
|
|
159
|
+
> already on npm. Recorded here rather than left there, because a consumer
|
|
160
|
+
> upgrading from 0.7.0 has no other account of what changed.
|
|
109
161
|
|
|
110
162
|
### Removed
|
|
111
163
|
|
package/dist/auth/hosted.d.ts
CHANGED
|
@@ -19,12 +19,34 @@ export interface HostedLoginConfig {
|
|
|
19
19
|
cookieName?: string;
|
|
20
20
|
/** Session-exchange path on the front door. Default `/session/token`. */
|
|
21
21
|
sessionPath?: string;
|
|
22
|
+
/** RP-initiated logout path on the front door. Default `/session/end-session`. */
|
|
23
|
+
endSessionPath?: string;
|
|
22
24
|
}
|
|
23
25
|
/**
|
|
24
26
|
* Build the redirect URL to the hosted front door, forwarding a best-effort
|
|
25
27
|
* absolute `returnTo` (honoured if the front door supports it).
|
|
26
28
|
*/
|
|
27
29
|
export declare function hostedLoginUrl(config: HostedLoginConfig, returnTo?: string): string;
|
|
30
|
+
/**
|
|
31
|
+
* Build the redirect URL that ENDS the hosted session — the mirror of
|
|
32
|
+
* `hostedLoginUrl`, and the only thing that actually signs a customer out on
|
|
33
|
+
* this flow.
|
|
34
|
+
*
|
|
35
|
+
* The cookie is the durable credential. Disposing of a bearer, clearing a
|
|
36
|
+
* local session, or calling the `customerLogout` mutation (which clears
|
|
37
|
+
* upstream provider tokens and nothing else) all leave it in place, and the
|
|
38
|
+
* next request re-establishes the customer from it. This URL points at the
|
|
39
|
+
* front door's end-session endpoint, which revokes the session row and clears
|
|
40
|
+
* the cookie before returning the browser to `returnTo`.
|
|
41
|
+
*
|
|
42
|
+
* A URL builder, deliberately: no transport, no CORS surface, no CSRF header,
|
|
43
|
+
* and no JavaScript required at the consumer. Server-side logout is
|
|
44
|
+
* `return redirect(hostedLogoutUrl(config, clientId, returnTo))`.
|
|
45
|
+
*
|
|
46
|
+
* `returnTo` must be an absolute URL on an origin registered for `clientId`;
|
|
47
|
+
* the platform refuses anything else. Omit it for a bare 204 with no redirect.
|
|
48
|
+
*/
|
|
49
|
+
export declare function hostedLogoutUrl(config: HostedLoginConfig, clientId: string, returnTo?: string): string;
|
|
28
50
|
/** The identity + bearer returned by a successful hosted-session exchange. */
|
|
29
51
|
export interface HostedSession {
|
|
30
52
|
token: string;
|
package/dist/auth/index.d.ts
CHANGED
|
@@ -14,7 +14,7 @@ export { customerLogin, customerRegister, customerRequestOTP, customerLoginOTP,
|
|
|
14
14
|
export type { FoirAuthTokens, FoirCustomer, FoirUser, SessionAdapter, RequireAuthOptions, RequireAdminOptions, } from './auth';
|
|
15
15
|
export { AUTH_OPS } from './ops';
|
|
16
16
|
export type { AuthOpName, AuthOpOptions } from './ops';
|
|
17
|
-
export { hostedLoginUrl, fetchHostedSession } from './hosted';
|
|
17
|
+
export { hostedLoginUrl, hostedLogoutUrl, fetchHostedSession } from './hosted';
|
|
18
18
|
export type { HostedLoginConfig, HostedSession } from './hosted';
|
|
19
19
|
export { createFoirSessionClient } from './session-client';
|
|
20
20
|
export type { FoirSessionClient, FoirSessionConfig, FoirSessionUser, } from './session-client';
|
package/dist/auth.js
CHANGED
|
@@ -1111,6 +1111,7 @@ async function requireAdmin(adapter, options) {
|
|
|
1111
1111
|
// src/auth/hosted.ts
|
|
1112
1112
|
var DEFAULT_COOKIE_NAME = "foir_customer_session";
|
|
1113
1113
|
var DEFAULT_SESSION_PATH = "/session/token";
|
|
1114
|
+
var DEFAULT_END_SESSION_PATH = "/session/end-session";
|
|
1114
1115
|
function hostedLoginUrl(config, returnTo) {
|
|
1115
1116
|
const dest = new URL(config.loginOrigin);
|
|
1116
1117
|
if (returnTo && returnTo !== "/") {
|
|
@@ -1118,6 +1119,15 @@ function hostedLoginUrl(config, returnTo) {
|
|
|
1118
1119
|
}
|
|
1119
1120
|
return dest.toString();
|
|
1120
1121
|
}
|
|
1122
|
+
function hostedLogoutUrl(config, clientId, returnTo) {
|
|
1123
|
+
const path = config.endSessionPath ?? DEFAULT_END_SESSION_PATH;
|
|
1124
|
+
const dest = new URL(path, config.loginOrigin);
|
|
1125
|
+
dest.searchParams.set("client_id", clientId);
|
|
1126
|
+
if (returnTo) {
|
|
1127
|
+
dest.searchParams.set("post_logout_redirect_uri", returnTo);
|
|
1128
|
+
}
|
|
1129
|
+
return dest.toString();
|
|
1130
|
+
}
|
|
1121
1131
|
async function fetchHostedSession(request, config) {
|
|
1122
1132
|
const cookieName = config.cookieName ?? DEFAULT_COOKIE_NAME;
|
|
1123
1133
|
const sessionPath = config.sessionPath ?? DEFAULT_SESSION_PATH;
|
|
@@ -1313,6 +1323,7 @@ export {
|
|
|
1313
1323
|
getSessionCustomer,
|
|
1314
1324
|
getSessionToken,
|
|
1315
1325
|
hostedLoginUrl,
|
|
1326
|
+
hostedLogoutUrl,
|
|
1316
1327
|
loginWithOTP,
|
|
1317
1328
|
loginWithPassword,
|
|
1318
1329
|
myProviderToken,
|
package/dist/data/builtins.d.ts
CHANGED
|
@@ -132,6 +132,73 @@ export interface Richtext {
|
|
|
132
132
|
json: FoirJsonValue | null;
|
|
133
133
|
markdown: string | null;
|
|
134
134
|
}
|
|
135
|
+
/**
|
|
136
|
+
* One run of styled text inside a passage.
|
|
137
|
+
*
|
|
138
|
+
* `marks` are named — `strong`, `em`, `code`, or a key into the passage's
|
|
139
|
+
* `markDefs` for anything that carries data (a link, and nothing else today).
|
|
140
|
+
* The bitmask the old editor stored is gone.
|
|
141
|
+
*/
|
|
142
|
+
export interface ProseSpan {
|
|
143
|
+
__typename?: 'ProseSpan';
|
|
144
|
+
text: string | null;
|
|
145
|
+
marks: Array<string | null> | null;
|
|
146
|
+
}
|
|
147
|
+
/**
|
|
148
|
+
* A text entry in a prose flow — a paragraph, a heading, a quote, a list item.
|
|
149
|
+
*
|
|
150
|
+
* `kind` is the semantic shape and `token` is the design-token override that
|
|
151
|
+
* beats it when set. `list` + `level` carry list nesting flat rather than as a
|
|
152
|
+
* tree. A soft break inside a passage is a `\n` in a span's text, not a
|
|
153
|
+
* separate entry.
|
|
154
|
+
*
|
|
155
|
+
* `markDefs` stays an open JSON leaf by declaration: def types are extensible,
|
|
156
|
+
* and a typed object over an open shape would drop what it does not know.
|
|
157
|
+
*/
|
|
158
|
+
export interface Passage {
|
|
159
|
+
__typename?: 'Passage';
|
|
160
|
+
_key: string | null;
|
|
161
|
+
kind: string | null;
|
|
162
|
+
token: string | null;
|
|
163
|
+
align: string | null;
|
|
164
|
+
list: string | null;
|
|
165
|
+
level: number | null;
|
|
166
|
+
language: string | null;
|
|
167
|
+
spans: Array<ProseSpan | null> | null;
|
|
168
|
+
markDefs: FoirJsonValue | null;
|
|
169
|
+
}
|
|
170
|
+
/**
|
|
171
|
+
* A prose field's read projection.
|
|
172
|
+
*
|
|
173
|
+
* `entries` is the typed reading and the one that keeps prose structured —
|
|
174
|
+
* `Passage` for a text-only field, and a union of `Passage` with the field's
|
|
175
|
+
* admitted embeds for one that places models. `html` and `markdown` are the
|
|
176
|
+
* passages only: an embed is omitted from both BY DECLARATION rather than
|
|
177
|
+
* rendered as invented markup, so a consumer that wants the embeds reads
|
|
178
|
+
* `entries`. `json` is the declared flow verbatim — the lossless escape hatch
|
|
179
|
+
* where an entry nobody recognises always survives.
|
|
180
|
+
*
|
|
181
|
+
* `E` is the entries element, filled in per field by `foir types`.
|
|
182
|
+
*/
|
|
183
|
+
export interface Prose<E = Passage> {
|
|
184
|
+
html: string | null;
|
|
185
|
+
markdown: string | null;
|
|
186
|
+
json: FoirJsonValue | null;
|
|
187
|
+
entries: Array<E | null> | null;
|
|
188
|
+
}
|
|
189
|
+
/**
|
|
190
|
+
* One ancestor of a hierarchy record, root-first.
|
|
191
|
+
*
|
|
192
|
+
* Identity only, by design: a child's public URL already exposes every
|
|
193
|
+
* ancestor's slug, so the walk never widens content visibility. Anything more
|
|
194
|
+
* than identity goes through the `parent` reference like any other read.
|
|
195
|
+
*/
|
|
196
|
+
export interface RecordAncestor {
|
|
197
|
+
__typename?: 'RecordAncestor';
|
|
198
|
+
_id: string;
|
|
199
|
+
_naturalKey: string | null;
|
|
200
|
+
_modelKey: string | null;
|
|
201
|
+
}
|
|
135
202
|
/**
|
|
136
203
|
* A reference whose target model is not pinned by the field's declaration.
|
|
137
204
|
*
|
package/dist/data/index.d.ts
CHANGED
|
@@ -44,12 +44,12 @@
|
|
|
44
44
|
export { createFoirClient, createFoirClientFromEnv } from './client';
|
|
45
45
|
export type { FoirClient, FoirClientCore, FoirModelClient, FoirNamespaceClient } from './client';
|
|
46
46
|
export { fetchFoirManifest } from './manifest';
|
|
47
|
-
export type { FoirManifest, FoirManifestComposite, FoirManifestModel, FoirManifestNamespace, FoirManifestOp, FoirManifestOpPayload, FoirManifestRelation, FoirManifestScalar, FoirManifestSelection, FoirManifestSelectionField, FoirManifestSelectionMember, FoirManifestSelectionUnion, FoirManifestSubscription, FoirManifestSubscriptionArgScope, FoirManifestUnclassifiedField, } from './manifest';
|
|
47
|
+
export type { FoirManifest, FoirManifestComposite, FoirManifestModel, FoirManifestNamespace, FoirManifestOp, FoirManifestOpPayload, FoirManifestRelation, FoirManifestScalar, FoirManifestSelection, FoirManifestSelectionField, FoirManifestSelectionMember, FoirManifestSelectionUnion, FoirManifestStructural, FoirManifestSubscription, FoirManifestSubscriptionArgScope, FoirManifestUnclassifiedField, } from './manifest';
|
|
48
48
|
export { planFoirModelCall, planFoirNamespaceCall } from './document';
|
|
49
49
|
export type { FoirCall, FoirDocumentPlan, FoirNamespaceCall, FoirNamespaceSelections, FoirRecordPath, FoirSelectionModel, FoirSelectionNamespace, FoirSelections, FoirSelectionSource, FoirSelectionUnions, } from './document';
|
|
50
50
|
export { createFoirSubjectRegistry, recordFoirSubjects } from './subjects';
|
|
51
51
|
export type { FoirSubject, FoirSubjectEntry, FoirSubjectOptions, FoirSubjectOrigin, FoirSubjectRegistry, } from './subjects';
|
|
52
|
-
export type { CollabInfo, FileValue, FoirAccessGrant, FoirAccessLevel, FoirAccessSource, FoirAccessor, FoirCreateMyNoteArgs, FoirCustomerNote, FoirCustomerNoteAttachment, FoirDegraded, FoirDepthBelow, FoirDepthLevel, FoirDeviceType, FoirGranteeKind, FoirJsonValue, FoirMyAccess, FoirMyNotesArgs, FoirMyNotesResult, FoirNoteConfig, FoirNoteSubjectType, FoirPlatformType, FoirResolveContext, FoirResourceAccess, FoirUnexpandedRecord, FoirUpdateManyPayload, FoirVisibility, GeoPoint, Image, ImageFormat, ImageVariant, ImageVariantSet, MediaValue, Reference, Richtext, Video, } from './builtins';
|
|
52
|
+
export type { CollabInfo, FileValue, FoirAccessGrant, FoirAccessLevel, FoirAccessSource, FoirAccessor, FoirCreateMyNoteArgs, FoirCustomerNote, FoirCustomerNoteAttachment, FoirDegraded, FoirDepthBelow, FoirDepthLevel, FoirDeviceType, FoirGranteeKind, FoirJsonValue, FoirMyAccess, FoirMyNotesArgs, FoirMyNotesResult, FoirNoteConfig, FoirNoteSubjectType, FoirPlatformType, FoirResolveContext, FoirResourceAccess, FoirUnexpandedRecord, FoirUpdateManyPayload, FoirVisibility, GeoPoint, Image, ImageFormat, ImageVariant, ImageVariantSet, MediaValue, Passage, Prose, ProseSpan, RecordAncestor, Reference, Richtext, Video, } from './builtins';
|
|
53
53
|
/**
|
|
54
54
|
* Pre-TTS-1391 spellings. The `<Name>Block` wrappers and the `<Name>Value`
|
|
55
55
|
* split are the same thing as the types above — an item IS its value — so each
|
package/dist/data/manifest.d.ts
CHANGED
|
@@ -139,6 +139,23 @@ export interface FoirManifestOpPayload {
|
|
|
139
139
|
*/
|
|
140
140
|
error?: string;
|
|
141
141
|
}
|
|
142
|
+
/**
|
|
143
|
+
* A platform-owned structural field: a prose wrapper, or the hierarchy walk's
|
|
144
|
+
* `ancestors`. Nested and always returned, like a composite — but there is no
|
|
145
|
+
* model behind it, so the entry names its TYPE (`Prose`, `ProseCta`,
|
|
146
|
+
* `RecordAncestor`) and the shape is `builtins.ts`'s.
|
|
147
|
+
*
|
|
148
|
+
* ABSENT on a server that predates the bucket, where these fields landed in
|
|
149
|
+
* `unclassifiedFields` and dropped out of the selection entirely. Widen on
|
|
150
|
+
* absent, as everywhere else in this file.
|
|
151
|
+
*/
|
|
152
|
+
export interface FoirManifestStructural {
|
|
153
|
+
key: string;
|
|
154
|
+
type: string;
|
|
155
|
+
list: boolean;
|
|
156
|
+
nullable: boolean;
|
|
157
|
+
deprecated?: boolean;
|
|
158
|
+
}
|
|
142
159
|
/** A built field the projection has no bucket for. Reported rather than dropped. */
|
|
143
160
|
export interface FoirManifestUnclassifiedField {
|
|
144
161
|
key: string;
|
|
@@ -172,12 +189,14 @@ export interface FoirManifestModel {
|
|
|
172
189
|
scalars: FoirManifestScalar[];
|
|
173
190
|
relations: FoirManifestRelation[];
|
|
174
191
|
composites: FoirManifestComposite[];
|
|
192
|
+
/** Platform-owned structural fields — prose wrappers, `ancestors`. */
|
|
193
|
+
structurals?: FoirManifestStructural[];
|
|
175
194
|
/**
|
|
176
|
-
*
|
|
177
|
-
*
|
|
178
|
-
* `
|
|
179
|
-
*
|
|
180
|
-
*
|
|
195
|
+
* Union field key → member model keys. Members that are platform primitives
|
|
196
|
+
* appear under their lowercase token (`richtext`, `image`, `video`, `file`,
|
|
197
|
+
* `reference`, `geopoint`) and have NO entry in `models` — they are
|
|
198
|
+
* platform-owned, identical in every project, and typed statically by
|
|
199
|
+
* `builtins.ts`.
|
|
181
200
|
*/
|
|
182
201
|
unions?: Record<string, string[]>;
|
|
183
202
|
/** Op names of this model's typed lookups. Each also appears in `ops`. */
|