@plitzi/sdk-shared 0.37.2 → 0.37.3

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.
Files changed (184) hide show
  1. package/CHANGELOG.md +1146 -0
  2. package/dist/actions/access.d.ts +12 -0
  3. package/dist/actions/access.mjs +13 -0
  4. package/dist/actions/functions.d.ts +27 -0
  5. package/dist/actions/functions.mjs +18 -0
  6. package/dist/actions/index.d.ts +4 -0
  7. package/dist/actions/index.mjs +9 -7
  8. package/dist/auth/index.d.ts +2 -0
  9. package/dist/auth/index.mjs +2 -1
  10. package/dist/auth/visitorRoles.d.ts +27 -0
  11. package/dist/auth/visitorRoles.mjs +48 -0
  12. package/dist/authoring/builder.mjs +1 -0
  13. package/dist/authoring/declare.d.ts +53 -0
  14. package/dist/authoring/declare.mjs +2 -2
  15. package/dist/authoring/index.mjs +5 -5
  16. package/dist/authoring/paramSpec.d.ts +1 -1
  17. package/dist/authoring/paramSpec.mjs +1 -0
  18. package/dist/authoring/spaceCallbacks.mjs +2 -2
  19. package/dist/dataSource/computed.d.ts +21 -0
  20. package/dist/dataSource/computed.mjs +45 -0
  21. package/dist/dataSource/getBindingsDetails.mjs +35 -34
  22. package/dist/dataSource/index.d.ts +1 -0
  23. package/dist/dataSource/index.mjs +7 -6
  24. package/dist/dataSource/utility/not.mjs +4 -7
  25. package/dist/dataSource/utility/stringToArray.mjs +1 -1
  26. package/dist/dataSource/utility/truthiness.d.ts +1 -0
  27. package/dist/dataSource/utility/truthiness.mjs +8 -0
  28. package/dist/dataSource/utility/twigTemplate.d.ts +2 -1
  29. package/dist/dataSource/utility/twigTemplate.mjs +29 -17
  30. package/dist/devTools/utils/PlitziConsole.mjs +22 -22
  31. package/dist/helpers/cookies.d.ts +10 -0
  32. package/dist/helpers/cookies.mjs +19 -0
  33. package/dist/helpers/fetchManifest.d.ts +9 -0
  34. package/dist/helpers/fetchManifest.mjs +3 -6
  35. package/dist/helpers/formatDate.d.ts +5 -3
  36. package/dist/helpers/formatDate.mjs +34 -36
  37. package/dist/helpers/index.d.ts +2 -0
  38. package/dist/helpers/index.mjs +18 -14
  39. package/dist/helpers/isDate.d.ts +7 -0
  40. package/dist/helpers/isDate.mjs +15 -0
  41. package/dist/helpers/keys.d.ts +42 -0
  42. package/dist/helpers/keys.mjs +91 -0
  43. package/dist/helpers/twigWrapper/AST.d.ts +2 -2
  44. package/dist/helpers/twigWrapper/Evaluator/Evaluator.d.ts +12 -2
  45. package/dist/helpers/twigWrapper/Evaluator/Evaluator.mjs +57 -34
  46. package/dist/helpers/twigWrapper/Evaluator/index.d.ts +1 -1
  47. package/dist/helpers/twigWrapper/Evaluator/index.mjs +2 -2
  48. package/dist/helpers/twigWrapper/Parser/ExpressionParser.d.ts +2 -2
  49. package/dist/helpers/twigWrapper/Parser/ExpressionParser.mjs +147 -34
  50. package/dist/helpers/twigWrapper/Parser/Parser.d.ts +2 -1
  51. package/dist/helpers/twigWrapper/Parser/Parser.mjs +21 -20
  52. package/dist/helpers/twigWrapper/filters/filters.mjs +130 -112
  53. package/dist/helpers/twigWrapper/index.d.ts +5 -2
  54. package/dist/helpers/twigWrapper/index.mjs +7 -5
  55. package/dist/helpers/twigWrapper/inspectTemplate.d.ts +23 -0
  56. package/dist/helpers/twigWrapper/inspectTemplate.mjs +110 -0
  57. package/dist/helpers/twigWrapper/processTwig/helpers.d.ts +7 -0
  58. package/dist/helpers/twigWrapper/processTwig/helpers.mjs +2 -1
  59. package/dist/helpers/twigWrapper/processTwig/index.d.ts +2 -1
  60. package/dist/helpers/twigWrapper/processTwig/index.mjs +3 -2
  61. package/dist/helpers/twigWrapper/processTwig/processTwig.d.ts +28 -0
  62. package/dist/helpers/twigWrapper/processTwig/processTwig.mjs +73 -16
  63. package/dist/helpers/twigWrapper/processTwig/resolveStepParam.d.ts +17 -0
  64. package/dist/helpers/twigWrapper/processTwig/resolveStepParam.mjs +14 -0
  65. package/dist/helpers/twigWrapper/templateRoots.d.ts +11 -0
  66. package/dist/helpers/twigWrapper/templateRoots.mjs +4 -4
  67. package/dist/helpers/twigWrapper/tokens/hasTemplateSyntax.d.ts +1 -1
  68. package/dist/history/describe.d.ts +29 -0
  69. package/dist/history/describe.mjs +93 -0
  70. package/dist/history/diff.d.ts +33 -0
  71. package/dist/history/diff.mjs +73 -0
  72. package/dist/history/index.d.ts +3 -0
  73. package/dist/history/index.mjs +3 -0
  74. package/dist/history/types.d.ts +48 -0
  75. package/dist/history/types.mjs +0 -0
  76. package/dist/index.d.ts +1 -0
  77. package/dist/index.mjs +77 -66
  78. package/dist/navigation/index.d.ts +1 -1
  79. package/dist/navigation/index.mjs +2 -2
  80. package/dist/navigation/routes.d.ts +11 -1
  81. package/dist/navigation/routes.mjs +15 -10
  82. package/dist/network/graphql/builder/Mutations/Space/SpaceFixIssuesMutation.d.ts +14 -0
  83. package/dist/network/graphql/builder/Mutations/Space/SpaceFixIssuesMutation.mjs +16 -0
  84. package/dist/network/graphql/builder/Mutations/Space/SpaceUpdatePluginMutation.d.ts +4 -0
  85. package/dist/network/graphql/builder/Mutations/Space/SpaceUpdatePluginMutation.mjs +2 -2
  86. package/dist/network/graphql/builder/Mutations/Space/actions/SpaceRunActionMutation.mjs +1 -0
  87. package/dist/network/graphql/builder/Mutations/Space/functions/SpaceRemoveFunctionsMutation.d.ts +3 -0
  88. package/dist/network/graphql/builder/Mutations/Space/functions/SpaceRemoveFunctionsMutation.mjs +9 -0
  89. package/dist/network/graphql/builder/Mutations/Space/functions/SpaceSaveFunctionsMutation.d.ts +11 -0
  90. package/dist/network/graphql/builder/Mutations/Space/functions/SpaceSaveFunctionsMutation.mjs +24 -0
  91. package/dist/network/graphql/builder/Mutations/Space/functions/SpaceTryFunctionMutation.d.ts +4 -0
  92. package/dist/network/graphql/builder/Mutations/Space/functions/SpaceTryFunctionMutation.mjs +15 -0
  93. package/dist/network/graphql/builder/Mutations/Space/runtime/SpaceRemoveRuntimeMutation.d.ts +2 -0
  94. package/dist/network/graphql/builder/Mutations/Space/runtime/SpaceRemoveRuntimeMutation.mjs +9 -0
  95. package/dist/network/graphql/builder/Mutations/Space/runtime/SpaceRemoveRuntimeVariableMutation.d.ts +2 -0
  96. package/dist/network/graphql/builder/Mutations/Space/runtime/SpaceRemoveRuntimeVariableMutation.mjs +9 -0
  97. package/dist/network/graphql/builder/Mutations/Space/runtime/SpaceSetRuntimeSizeMutation.d.ts +2 -0
  98. package/dist/network/graphql/builder/Mutations/Space/runtime/SpaceSetRuntimeSizeMutation.mjs +9 -0
  99. package/dist/network/graphql/builder/Mutations/Space/runtime/SpaceSetRuntimeVariableMutation.d.ts +2 -0
  100. package/dist/network/graphql/builder/Mutations/Space/runtime/SpaceSetRuntimeVariableMutation.mjs +9 -0
  101. package/dist/network/graphql/builder/Mutations/Space/runtime/SpaceStartRuntimeMutation.d.ts +2 -0
  102. package/dist/network/graphql/builder/Mutations/Space/runtime/SpaceStartRuntimeMutation.mjs +9 -0
  103. package/dist/network/graphql/builder/Mutations/Space/runtime/SpaceStopRuntimeMutation.d.ts +2 -0
  104. package/dist/network/graphql/builder/Mutations/Space/runtime/SpaceStopRuntimeMutation.mjs +9 -0
  105. package/dist/network/graphql/builder/Mutations/Space/visitors/SpaceAddVisitorMutation.d.ts +2 -0
  106. package/dist/network/graphql/builder/Mutations/Space/visitors/SpaceAddVisitorMutation.mjs +11 -0
  107. package/dist/network/graphql/builder/Mutations/Space/visitors/SpaceRemoveVisitorMutation.d.ts +2 -0
  108. package/dist/network/graphql/builder/Mutations/Space/visitors/SpaceRemoveVisitorMutation.mjs +11 -0
  109. package/dist/network/graphql/builder/Mutations/index.d.ts +28 -0
  110. package/dist/network/graphql/builder/Mutations/index.mjs +108 -84
  111. package/dist/network/graphql/builder/Queries/Space/SpaceChangesQuery.d.ts +23 -0
  112. package/dist/network/graphql/builder/Queries/Space/SpaceChangesQuery.mjs +49 -0
  113. package/dist/network/graphql/builder/Queries/Space/SpaceFunctionsQuery.d.ts +6 -0
  114. package/dist/network/graphql/builder/Queries/Space/SpaceFunctionsQuery.mjs +13 -0
  115. package/dist/network/graphql/builder/Queries/Space/SpaceIssuesQuery.d.ts +17 -0
  116. package/dist/network/graphql/builder/Queries/Space/SpaceIssuesQuery.mjs +22 -0
  117. package/dist/network/graphql/builder/Queries/Space/SpaceRuntimeQuery.d.ts +6 -0
  118. package/dist/network/graphql/builder/Queries/Space/SpaceRuntimeQuery.mjs +32 -0
  119. package/dist/network/graphql/builder/Queries/Space/SpaceVisitorsQuery.d.ts +6 -0
  120. package/dist/network/graphql/builder/Queries/Space/SpaceVisitorsQuery.mjs +16 -0
  121. package/dist/network/graphql/builder/Queries/index.d.ts +17 -3
  122. package/dist/network/graphql/builder/Queries/index.mjs +30 -22
  123. package/dist/network/graphql/sdk/Mutations/index.d.ts +1 -1
  124. package/dist/network/graphql/sdk/Queries/InitQuery.d.ts +1 -1
  125. package/dist/network/graphql/sdk/Queries/InitQuery.mjs +2 -91
  126. package/dist/network/graphql/sdk/Queries/Segment/SegmentQuery.d.ts +1 -1
  127. package/dist/network/graphql/sdk/Queries/Segment/SegmentQuery.mjs +2 -44
  128. package/dist/network/graphql/sdk/Queries/Segment/SegmentsQuery.d.ts +1 -1
  129. package/dist/network/graphql/sdk/Queries/Segment/SegmentsQuery.mjs +2 -55
  130. package/dist/network/graphql/sdk/Queries/index.d.ts +1 -5
  131. package/dist/network/index.mjs +7 -7
  132. package/dist/network/spaceEvents.d.ts +33 -3
  133. package/dist/network/spaceEvents.mjs +102 -89
  134. package/dist/realtime/client.d.ts +46 -0
  135. package/dist/realtime/client.mjs +192 -0
  136. package/dist/realtime/index.d.ts +6 -0
  137. package/dist/realtime/index.mjs +4 -0
  138. package/dist/realtime/presence.d.ts +38 -0
  139. package/dist/realtime/presence.mjs +70 -0
  140. package/dist/realtime/topics.d.ts +36 -0
  141. package/dist/realtime/topics.mjs +25 -0
  142. package/dist/server/actions/useRealtimeSync.d.ts +9 -0
  143. package/dist/server/actions/useRealtimeSync.mjs +7 -0
  144. package/dist/state/index.d.ts +1 -0
  145. package/dist/state/index.mjs +3 -2
  146. package/dist/state/paintedState.d.ts +52 -0
  147. package/dist/state/paintedState.mjs +37 -0
  148. package/dist/state/runtimeStatePersist.d.ts +8 -1
  149. package/dist/state/runtimeStatePersist.mjs +79 -29
  150. package/dist/store/index.d.ts +45 -45
  151. package/dist/store/renderSettings.d.ts +6 -3
  152. package/dist/store/tracing/index.d.ts +1 -0
  153. package/dist/store/tracing/tracingCollector.d.ts +17 -1
  154. package/dist/store/tracing/tracingCollector.mjs +5 -0
  155. package/dist/style/index.d.ts +1 -0
  156. package/dist/style/index.mjs +3 -2
  157. package/dist/style/runtimeStyle.d.ts +29 -0
  158. package/dist/style/runtimeStyle.mjs +7 -0
  159. package/dist/style/styleConstants.d.ts +3 -2
  160. package/dist/style/styleConstants.mjs +2 -0
  161. package/dist/style/styleStates.d.ts +14 -1
  162. package/dist/style/styleStates.mjs +10 -7
  163. package/dist/theme/ThemeProvider.mjs +35 -29
  164. package/dist/theme/themeCookie.mjs +11 -15
  165. package/dist/types/ActionTypes.d.ts +4 -0
  166. package/dist/types/AuthTypes.d.ts +11 -1
  167. package/dist/types/CommonTypes.d.ts +6 -0
  168. package/dist/types/FunctionTypes.d.ts +52 -0
  169. package/dist/types/FunctionTypes.mjs +0 -0
  170. package/dist/types/PluginTypes.d.ts +0 -1
  171. package/dist/types/RealtimeTypes.d.ts +94 -0
  172. package/dist/types/RealtimeTypes.mjs +0 -0
  173. package/dist/types/SchemaTypes.d.ts +54 -0
  174. package/dist/types/SchemaTypes.mjs +8 -0
  175. package/dist/types/ServerTypes.d.ts +259 -15
  176. package/dist/types/SpaceTypes.d.ts +53 -0
  177. package/dist/types/StateTypes.d.ts +6 -0
  178. package/dist/types/StoreTypes.d.ts +11 -0
  179. package/dist/types/index.d.ts +2 -0
  180. package/dist/types/index.mjs +3 -2
  181. package/package.json +172 -11
  182. package/vite.config.ts +0 -12
  183. package/dist/network/graphql/builder/Queries/PluginsQuery.d.ts +0 -9
  184. package/dist/network/graphql/builder/Queries/PluginsQuery.mjs +0 -54
@@ -1,4 +1,5 @@
1
1
  import { InteractionCallbackParamValues, InteractionCallbackType } from './InteractionTypes';
2
+ import { ChannelDeclarations } from './RealtimeTypes';
2
3
  import { Style } from './StyleTypes';
3
4
  import { RuleGroup } from '@plitzi/plitzi-ui/QueryBuilder';
4
5
  export type ElementRuntime = 'server' | 'client' | 'shared';
@@ -44,6 +45,15 @@ export type ElementBinding = {
44
45
  enabled?: boolean;
45
46
  to: string;
46
47
  };
48
+ /**
49
+ * What a trigger does when it fires again while the flow it started is still running.
50
+ *
51
+ * - `skip` (the default): the new firing is ignored — what keeps a double click from submitting twice.
52
+ * - `parallel`: every firing runs its own flow, at the same time.
53
+ * - `queue`: every firing runs, one after another, in the order they came — none lost, none overlapping.
54
+ */
55
+ export type WhileRunning = 'skip' | 'parallel' | 'queue';
56
+ export declare const WHILE_RUNNING_MODES: readonly WhileRunning[];
47
57
  export type ElementInteraction<T extends Record<string, unknown> = Record<string, unknown>> = {
48
58
  id: string;
49
59
  title: string;
@@ -57,6 +67,8 @@ export type ElementInteraction<T extends Record<string, unknown> = Record<string
57
67
  flowId: string;
58
68
  enabled: boolean;
59
69
  when?: RuleGroup;
70
+ /** On a trigger only: what a firing does while this flow is still running. `skip` when absent. */
71
+ whileRunning?: WhileRunning;
60
72
  };
61
73
  export type ElementDefinition = {
62
74
  rootId: Element['id'];
@@ -123,7 +135,30 @@ export type Schema = {
123
135
  settings: {
124
136
  keepState?: boolean;
125
137
  stateStorage?: 'localStorage' | 'sessionStorage';
138
+ /**
139
+ * Keys of `runtime.state` that are never kept, even with `keepState` on: they are not written, not brought back,
140
+ * and a value one of them already holds survives the moment the rest is restored. For state that must start fresh
141
+ * on every visit — a demo, a panel somebody left open, a step of a walkthrough. Top-level keys, as `setState`
142
+ * writes them.
143
+ */
144
+ transientState?: string[];
145
+ /**
146
+ * Keys of `runtime.state` the first paint depends on — the tool a toolbar shows, a name in an avatar — kept in a
147
+ * cookie as well as in `stateStorage`, so the server renders with them and the page does not swap them in after
148
+ * hydration. Small values only: the cookie travels with every request and holds at most a few kilobytes. Needs
149
+ * `keepState`; a key cannot be both painted and transient. Top-level keys, as `setState` writes them.
150
+ */
151
+ paintedState?: string[];
126
152
  customCss: string;
153
+ /**
154
+ * The roles a signed-in visitor may hold in this space, each with the permissions it gives:
155
+ * `{ author: ['postPublish'] }`. They are what an action's `access: 'role'` and a page's `can()` are answered from
156
+ * — a visitor holds exactly the permissions of their roles here, never those of their account anywhere else.
157
+ *
158
+ * Declared by the space, so they are published, versioned and exported with it. WHO holds which is not: that is a
159
+ * list of people, kept by the platform the space runs on, and never part of a document anybody can read.
160
+ */
161
+ visitorRoles?: Record<string, string[]>;
127
162
  /** `basic` covers any HTTP+JSON backend by configuration; anything else is a name someone registered. */
128
163
  userProvider?: 'basic' | 'custom' | '' | (string & {});
129
164
  tokenStorage?: 'localStorage' | 'sessionStorage' | '';
@@ -151,6 +186,13 @@ export type Schema = {
151
186
  * session itself, which is the case whenever `loginUrl` is your own API.
152
187
  */
153
188
  sessionExchangeUrl?: string;
189
+ /**
190
+ * Where a sign-in that owed a second factor is completed: a password the backend answered with `mfaRequired` and
191
+ * an `mfaToken` resolves `auth.login` to `{ ok: false, reason: 'mfa', mfaToken }`, and `auth.login` with `mode:
192
+ * 'mfa'` posts `{ mfaToken, code }` here and adopts the session it answers with. Leave empty when the backend has
193
+ * no second factor.
194
+ */
195
+ mfaUrl?: string;
154
196
  /**
155
197
  * What to do on a page that requires a session while the stored one is being re-checked. `optimistic` (the
156
198
  * default) renders from the stored session and signs out if the check disagrees; `strict` waits for the answer,
@@ -167,6 +209,18 @@ export type Schema = {
167
209
  * `false` there cannot be turned around from here. Never `devMode`, which makes a deployment a development server.
168
210
  */
169
211
  debugMode?: boolean;
212
+ /**
213
+ * Values the space computes once and reads everywhere, by name: `{ xp: '{{ state.favourites|length * 10 }}' }` is
214
+ * read as `{{ computed.xp }}` in any binding, attribute or step. Each is a template over the global sources and the
215
+ * values declared before it (`computed.<earlier>`), re-evaluated when any of them changes. A template that is one
216
+ * `{{ expression }}` gives its value (a number, a list); anything else gives text.
217
+ */
218
+ computed?: Record<string, string>;
219
+ /**
220
+ * The realtime channels the space offers, by topic pattern: `{ 'board:{id}': { access: { mode: 'public' } } }`.
221
+ * A page subscribes to and publishes on a topic one of them matches, and on nothing else.
222
+ */
223
+ channels?: ChannelDeclarations;
170
224
  };
171
225
  rsc?: SchemaRsc;
172
226
  pages: Element['id'][];
@@ -0,0 +1,8 @@
1
+ //#region src/types/SchemaTypes.ts
2
+ var e = [
3
+ "skip",
4
+ "parallel",
5
+ "queue"
6
+ ];
7
+ //#endregion
8
+ export { e as WHILE_RUNNING_MODES };
@@ -1,9 +1,12 @@
1
- import { ActionEmailConfig, ActionEntry, ActionJobQueue, ActionLimits, ActionRejectReason, ActionRunSummary, ActionRejectRecord, ActionRunRecord, ActionRunStatus, ActionTaskDescriptor, ActionTriggerType } from './ActionTypes';
1
+ import { ActionEmailConfig, ActionEntry, ActionJobQueue, ActionLimits, ActionRejectReason, ActionRunSummary, ActionRejectRecord, ActionRunRecord, ActionRunReport, ActionRunStatus, ActionTaskDescriptor, ActionTriggerType } from './ActionTypes';
2
2
  import { Environment } from './CommonTypes';
3
3
  import { ConnectorEntry } from './ConnectorTypes';
4
+ import { FunctionsDraft, FunctionsSaveResult } from './FunctionTypes';
5
+ import { SSRRealtimeConfig } from './RealtimeTypes';
4
6
  import { Schema } from './SchemaTypes';
5
7
  import { AnalyticsConfig, OfflineDataRaw } from './SdkTypes';
6
8
  import { FontHead, Style } from './StyleTypes';
9
+ import { SpaceChange } from '../history/types';
7
10
  import { IncomingHttpHeaders } from 'node:http';
8
11
  import { FC } from 'react';
9
12
  export type ServerEnvironment = 'development' | 'production' | 'staging' | 'local';
@@ -24,8 +27,15 @@ export type SSRRequest = {
24
27
  query: Record<string, string>;
25
28
  /** Raw request body. Populated only for endpoints that consume it (e.g. the login/logout handlers). */
26
29
  body?: string;
30
+ /**
31
+ * The client's address, when the host resolved one — through the proxies it sits behind. Forgeable by a direct
32
+ * client like every forwarded header, so it names things (a session in a device list) and never decides anything.
33
+ */
34
+ ip?: string;
27
35
  ctx: SSRContext;
28
36
  };
37
+ /** A body's compressed forms, by content encoding — filled as they are first asked for. */
38
+ export type CompressedBodies = Partial<Record<'br' | 'gzip', Buffer>>;
29
39
  export type SSRResponseHelpers = {
30
40
  status: number;
31
41
  /** Multi-valued for the headers that genuinely are, `Set-Cookie` above all — see `setHeader`. */
@@ -37,8 +47,18 @@ export type SSRResponseHelpers = {
37
47
  /**
38
48
  * A `Buffer` is sent byte for byte and never compressed: it is how a binary reaches the wire — a font file, an
39
49
  * image — and what it holds is usually compressed already. A string keeps the encoding negotiation.
50
+ *
51
+ * `compressed` is where this body's compressed forms are kept, for a body that is sent again unchanged — a cached
52
+ * page, a static file. The first send of each encoding compresses and stores it; every later one sends the stored
53
+ * bytes. Without it a cache hit recompressed the same page on every request, which was nearly all the CPU a cached
54
+ * page cost.
55
+ *
56
+ * A function is a body read only when it is needed: when the stored form for this request's encoding is missing, or
57
+ * the client takes no compression. A static file is then read from disk once per encoding, not on every request.
40
58
  */
41
- send: (body: string | Buffer) => void;
59
+ send: (body: string | Buffer | (() => string), options?: {
60
+ compressed?: CompressedBodies;
61
+ }) => void;
42
62
  write: (chunk: string | Buffer) => void;
43
63
  end: () => void;
44
64
  };
@@ -170,6 +190,23 @@ export type SSRGrant = {
170
190
  userId?: number;
171
191
  canWrite: boolean;
172
192
  };
193
+ /** A page of a space's change history, newest first; `nextBefore` reads further back, null at the end. */
194
+ export type SSRChangePage = {
195
+ changes: SpaceChange[];
196
+ nextBefore: number | null;
197
+ };
198
+ /** What to read of the history: older than `before`, only the changes that touched `entityId`, `limit` at a time. */
199
+ export type SSRChangeQuery = {
200
+ before?: number;
201
+ entityId?: string;
202
+ limit: number;
203
+ };
204
+ /** Who a write is made for and which request made it, for a consumer that records its changes. Every document one
205
+ * request writes shares its `batch`: one `plitzi_apply`, read back as one change. */
206
+ export type SSRWriteContext = {
207
+ userId?: number;
208
+ batch: string;
209
+ };
173
210
  /**
174
211
  * A session, as the thing that issued it describes it. Deliberately free of transport: whoever mints one says what
175
212
  * the credentials are and when they die, and the server decides how they are carried — which is what lets a
@@ -325,13 +362,25 @@ export type SSRAdapters = {
325
362
  saveAction?: (spaceId: number, entry: ActionEntry) => Promise<void>;
326
363
  /** Remove one action by its identifier. Omitted alongside `saveAction` for a read-only deployment. */
327
364
  deleteAction?: (spaceId: number, actionId: string) => Promise<void>;
365
+ /** The space's own functions: the draft's source files, which copy of them it is and what they declare.
366
+ * Server-side code like the actions it serves — never a browser payload. When omitted, the MCP offers no functions
367
+ * resource and refuses the function ops. */
368
+ getFunctions?: (spaceId: number) => Promise<FunctionsDraft | undefined>;
369
+ /** Save the draft's functions, whole. The deployment builds and checks them and answers what is wrong where it is;
370
+ * `base` is the version the agent read, and a draft that moved on since is refused rather than overwritten. */
371
+ saveFunctions?: (spaceId: number, files: Record<string, string>, base: string, write: SSRWriteContext) => Promise<FunctionsSaveResult>;
372
+ /** Run one task of the draft's functions in the sandbox for the person behind the agent — the builder's Try. */
373
+ tryFunction?: (spaceId: number, task: string, params: Record<string, unknown>, write: SSRWriteContext) => Promise<ActionRunReport>;
328
374
  /** Persist the element schema mutated by the MCP `apply` tool. When omitted, `apply` reports `persisted: false`. */
329
- saveSchema?: (spaceId: number, environment: Environment, schema: Schema) => Promise<void>;
375
+ saveSchema?: (spaceId: number, environment: Environment, schema: Schema, write: SSRWriteContext) => Promise<void>;
330
376
  /** Persist the style document mutated by the MCP `apply` tool — store it as given. `style.cache` arrives already
331
377
  * compiled: the renderer serves that string and nothing else, so recomputing it is not a detail to delegate, and
332
378
  * asking every deployment to remember it was one bug each of them could write alone. When omitted, `apply`
333
379
  * reports `persisted: false`. */
334
- saveStyle?: (spaceId: number, environment: Environment, style: Style) => Promise<void>;
380
+ saveStyle?: (spaceId: number, environment: Environment, style: Style, write: SSRWriteContext) => Promise<void>;
381
+ /** The space's change history, read-only: what every writer saved, and for whom. When omitted, the MCP offers no
382
+ * history resource. */
383
+ getChanges?: (spaceId: number, environment: Environment, query: SSRChangeQuery) => Promise<SSRChangePage>;
335
384
  /** Who this request carries, if anyone. The adapter reads the credential and resolves it; the cookie it arrived
336
385
  * in was written by the server, from {@link SSRAuthCookie}. */
337
386
  getUser?: (req: SSRRequest) => Promise<SSRUser | undefined>;
@@ -469,6 +518,8 @@ export type ActionLookupsConfig = {
469
518
  listScheduledSpaces?: () => Promise<number[]>;
470
519
  getCredential?: (spaceId: number, identifier: string) => Promise<Record<string, string> | undefined>;
471
520
  getConnector?: (spaceId: number, connectorId: string, at?: SpaceRevision) => Promise<unknown>;
521
+ /** The space's own functions as of that revision — `SpaceFunctions` in `@plitzi/sdk-server/functions`. */
522
+ getFunctions?: (spaceId: number, at?: SpaceRevision) => Promise<unknown>;
472
523
  };
473
524
  export type SSRActionConfig = {
474
525
  /** URL path for the write endpoint, and the base for the action-addressed routes. Defaults to '/_action'. */
@@ -478,8 +529,6 @@ export type SSRActionConfig = {
478
529
  * the endpoint keeps answering element-addressed connector writes alone.
479
530
  */
480
531
  lookups?: ActionLookupsConfig;
481
- /** Deployment-owned tasks, shaped as `ActionTask` in `@plitzi/sdk-server/actions`. Validated at boot. */
482
- tasks?: unknown[];
483
532
  /** Ceilings for every run this server accepts. A document may tighten them, never widen them. */
484
533
  limits?: ActionLimits;
485
534
  /**
@@ -539,10 +588,15 @@ export type SSRActionConfig = {
539
588
  idempotency?: {
540
589
  replayTtlMs?: number;
541
590
  };
591
+ /**
592
+ * What each space's functions sign with (`ctx.sign` / `ctx.verify`): at least 32 characters, the same on every
593
+ * replica. Each space and environment signs with a key derived from it. Absent, spaces sign nothing.
594
+ */
595
+ signingSecret?: string;
542
596
  /**
543
597
  * Where the `kv` tasks keep things — shaped as `ActionKvAdapter` in `@plitzi/sdk-server/actions`.
544
598
  *
545
- * Five operations over strings, with no rule to obey: Redis, Memcached, a table, whatever this deployment
599
+ * Six operations over strings, with no rule to obey: Redis, Memcached, a table, whatever this deployment
546
600
  * already runs. How a counter BEHAVES — the key prefixing, the JSON round trip, and the rule that a window's
547
601
  * lifetime is set once by whoever created it — belongs to the server, not to the thing it writes into.
548
602
  *
@@ -555,6 +609,8 @@ export type SSRActionConfig = {
555
609
  delete: (key: string) => Promise<void>;
556
610
  increment: (key: string, amount: number) => Promise<number>;
557
611
  expire: (key: string, ttlSeconds: number) => Promise<void>;
612
+ /** Writes `next` only if the key holds `expected` (nothing, when undefined); answers whether it wrote. Atomic. */
613
+ swap: (key: string, expected: string | undefined, next: string, ttlSeconds?: number) => Promise<boolean>;
558
614
  };
559
615
  /**
560
616
  * Scheduled runs: the durable queue they wait in, how many this replica runs at once, and whether it produces.
@@ -650,8 +706,18 @@ export type SSRCompressionConfig = {
650
706
  encodings?: ('br' | 'gzip')[];
651
707
  /** Responses smaller than this many bytes go out uncompressed. Default 1024. */
652
708
  threshold?: number;
653
- /** Brotli quality, 0–11. Default 4 — past that the CPU cost outgrows the bytes saved on HTML. */
709
+ /**
710
+ * Brotli quality, 0–11, for a body compressed on every request — a page rendered for this request alone. Default 2:
711
+ * measured on a quarter core, going to 4 cost a tenth of the pages a second to save half a kilobyte on each.
712
+ */
654
713
  brotliQuality?: number;
714
+ /**
715
+ * Brotli quality, 0–11, for a body compressed once and kept — a cached page, a static file such as the SDK bundle.
716
+ * Default 6: paid once, and every later response is that much smaller (the SDK bundle 10% under quality 4), for
717
+ * the same memory as 4. 9 needs ~40 MB more to compress the bundle, which a 128 MB server does not have; 10 and
718
+ * 11 cost seconds, which the request that fills the cache would wait for.
719
+ */
720
+ keptBrotliQuality?: number;
655
721
  /** Gzip level, 0–9. Default 6. */
656
722
  gzipLevel?: number;
657
723
  };
@@ -676,6 +742,12 @@ export type SSRRscConfig = {
676
742
  elementTimeoutMs?: number;
677
743
  };
678
744
  /** What every log event carries, whatever layer it came from. */
745
+ /**
746
+ * How much a server says, from least to most: each level includes every one above it. `error` is what a production
747
+ * server shows unless told otherwise — something went wrong — and `warn`, `info` (every request answered, every
748
+ * plugin built) and `debug` are asked for. `silent` says nothing at all.
749
+ */
750
+ export type LogLevel = 'error' | 'warn' | 'info' | 'debug';
679
751
  type ServerLogEventBase = {
680
752
  /** Wall-clock duration of the work the event describes, in milliseconds. */
681
753
  durationMs: number;
@@ -771,7 +843,18 @@ export type ActionRejectLogEvent = ServerLogEventBase & {
771
843
  * are stripped from paths, tool arguments are reduced to their shape and a run to its steps. Two fields are NOT
772
844
  * anonymous and a consumer shipping these events must handle them accordingly: `clientIp` on a request event, and
773
845
  * the request path, which is kept verbatim because it is what makes the log usable. */
774
- export type ServerLogEvent = ServerRequestLogEvent | McpToolLogEvent | McpResourceLogEvent | ActionRunLogEvent | ActionRejectLogEvent;
846
+ /** Anything else the server has to say — a plugin rebuilt, a manifest that would not load — at its own level. */
847
+ export type ServerMessageLogEvent = {
848
+ kind: 'message';
849
+ level: LogLevel;
850
+ /** What is speaking: `SSR`, `RSC`, `Actions`, `auth`… — what a line used to start with in brackets. */
851
+ scope: string;
852
+ message: string;
853
+ ok: boolean;
854
+ error?: string;
855
+ timestamp: string;
856
+ };
857
+ export type ServerLogEvent = ServerRequestLogEvent | McpToolLogEvent | McpResourceLogEvent | ActionRunLogEvent | ActionRejectLogEvent | ServerMessageLogEvent;
775
858
  /** The sink a consumer provides to receive every {@link ServerLogEvent} (see `SSRServerConfig.logger`). */
776
859
  export type ServerLogger = (event: ServerLogEvent) => void;
777
860
  export type SSRServerConfig = {
@@ -800,6 +883,11 @@ export type SSRServerConfig = {
800
883
  /** Where a browser-obtained credential is handed over. Defaults to `/auth/exchange`; served only when the
801
884
  * `exchangeCredential` adapter is supplied. */
802
885
  exchangePath?: string | false;
886
+ /**
887
+ * Signing visitors in by redirect, through an OAuth 2.1 authorization server — see {@link SSRSignInConfig}. Served
888
+ * only with the `exchangeCredential` adapter, which is what turns what comes back into a session on this host.
889
+ */
890
+ signIn?: SSRSignInConfig;
803
891
  /** Naming and scope of the session cookies this server writes. See {@link SSRAuthCookie}. */
804
892
  authCookie?: SSRAuthCookie;
805
893
  templateFn?: SSRTemplateFn;
@@ -808,6 +896,13 @@ export type SSRServerConfig = {
808
896
  pluginsTtlMs?: number;
809
897
  /** Auto-download and cache plugins declared in the schema's offlineData.plugins list. Default: true. */
810
898
  autoLoadSchemaPlugins?: boolean;
899
+ /**
900
+ * Whether a schema plugin may be read from a private address — `localhost`, the network this server runs in. A
901
+ * plugin's address is typed by whoever edits a space and read from inside this server, so it answers to the rule
902
+ * every authored request does and is refused there; turn this on only on a development machine whose bucket is on
903
+ * localhost. Default: false.
904
+ */
905
+ allowPrivatePluginHosts?: boolean;
811
906
  /** Where this deployment serves the font files a space uploaded — see {@link SSRFontsConfig}. */
812
907
  fonts?: SSRFontsConfig;
813
908
  /** Omit client-side JS from the rendered page — useful for verifying SSR HTML without hydration. Default: false. */
@@ -824,13 +919,34 @@ export type SSRServerConfig = {
824
919
  rsc?: SSRRscConfig;
825
920
  /** Write endpoint for server-driven providers. Absent means the server serves reads only. */
826
921
  action?: SSRActionConfig;
922
+ /**
923
+ * Code of this server's own, and the sandbox for the spaces' — shaped as `FunctionsConfig` in
924
+ * `@plitzi/sdk-server/functions`. `native` is trusted code loaded in the process (a self-hosted server's tasks, or a
925
+ * platform's own); `runner` runs each space's functions, isolated.
926
+ */
927
+ functions?: {
928
+ native?: unknown[];
929
+ runner?: unknown;
930
+ limits?: Record<string, number>;
931
+ };
932
+ /** Realtime channels the spaces declare — see {@link SSRRealtimeConfig}. On, in memory, when absent. */
933
+ realtime?: SSRRealtimeConfig;
827
934
  /** Connector manifest and credential lookups — see {@link ConnectorLookupsConfig}. They serve the RSC read path
828
935
  * and the `/_action` write endpoint alike; without them neither can reach a connector. */
829
936
  connectors?: ConnectorLookupsConfig;
830
937
  /** Receives a {@link ServerLogEvent} for every HTTP request this server answers — whatever stage answered it
831
938
  * and whatever the outcome — plus every MCP tool call and resource read inside those requests. Without it the
832
- * server reports nothing per request (the MCP events still reach the console when `MCP_DEBUG=1`). */
939
+ * server reports nothing per request (the MCP events still reach the console when `MCP_DEBUG=1`). Everything
940
+ * else the server has to say — a failure, a plugin rebuilt — comes here too as a `message` event, and goes to the
941
+ * console when there is no logger. */
833
942
  logger?: ServerLogger;
943
+ /**
944
+ * The least severe thing worth saying — see {@link LogLevel}. `error` by default, `info` with `devMode`: a server
945
+ * in production reports what went wrong and nothing else, unless asked. A request that was answered is `info`, one
946
+ * that failed `error`; a refused action is `warn`. Below the level nothing is built, so a quiet server pays nothing
947
+ * per request for the log it is not keeping.
948
+ */
949
+ logLevel?: LogLevel | 'silent';
834
950
  /**
835
951
  * How responses are compressed. Omit for Brotli where the client takes it and gzip otherwise; `false` never
836
952
  * compresses, which is what to use when a proxy or CDN in front already does it.
@@ -849,6 +965,32 @@ export type SSRServerConfig = {
849
965
  host: string;
850
966
  label: string;
851
967
  }) => void;
968
+ /**
969
+ * How many processes serve this port. Node runs JavaScript on one thread, so one process renders on one core however
970
+ * many the machine has; each worker is a whole server of its own, and the connections are spread between them —
971
+ * more requests a second, and less time waiting behind another render.
972
+ *
973
+ * `true` / `'auto'`: one per core the process may actually use (a container's CPU quota included). `false`: one
974
+ * process. A number: that many, lowered to the cores there are (more only take turns on the same cores). Default: on
975
+ * under `NODE_ENV=production`, off otherwise — a development server and a test runner stay one process. The
976
+ * `SDK_SERVER_WORKERS` environment variable sets it when this does not.
977
+ *
978
+ * The workers are one server — one replica — and behave as one:
979
+ *
980
+ * - The stores kept in memory by default (an action's `kv`, the job queue, draft previews, the sign-in rate
981
+ * limit) are the primary's, and each worker reaches them over the cluster channel. A store the deployment
982
+ * supplies (Redis, a table) is used as it is.
983
+ * - The scheduler and the job consumers run in one worker only, so a schedule fires once and `jobs.workers` is the
984
+ * whole server's concurrency; if that worker dies, its replacement takes them over.
985
+ * - `server.cache.invalidate()`, `server.plugins.register()` and `server.plugins.invalidate()` reach every worker,
986
+ * whichever process calls them.
987
+ *
988
+ * Per worker: the rendered-page cache (each renders a page once), the plugin components, and the action run caps
989
+ * (`action.concurrency`: `perSpace`, `perProcess`, `renderPerProcess`), which a cluster of replicas already counts
990
+ * per replica. A plugin registered with a `component` stays in the process that registered it — register those
991
+ * where the server is created.
992
+ */
993
+ workers?: boolean | number | 'auto';
852
994
  adapters: SSRAdapters;
853
995
  /** Which request-handling services this server mounts: `ssr` on by default, `rsc` whenever
854
996
  * `adapters.getRscData` exists. Stages a companion package contributes are deliberately NOT flags here —
@@ -875,6 +1017,28 @@ export type SSRServerConfig = {
875
1017
  * `createServer` from `@plitzi/sdk-server` takes and what the SSR stages are handed, so a page stage reaches
876
1018
  * `getOfflineData` without asking whether it is there — while a stage typed to the bare context (anything from
877
1019
  * `@plitzi/sdk-mcp`, which also runs in servers that have neither) still has to check. */
1020
+ /**
1021
+ * A visitor signs in somewhere else and comes back signed in HERE: `GET <path>?return=/somewhere` sends them to the
1022
+ * authorization server, and `GET <path>/callback` takes the code it answers with, redeems it server to server and
1023
+ * hands the token to `exchangeCredential` — which is what makes the session, on this host, for this space.
1024
+ *
1025
+ * This server registers itself with the authorization server (RFC 7591) as the host the visitor is on, and proves the
1026
+ * exchange with PKCE. The state travels in a `__Host-` cookie, which no sibling host can set: a sign-in somebody else
1027
+ * started cannot be finished in this browser.
1028
+ */
1029
+ export type SSRSignInConfig = {
1030
+ /** What `exchangeCredential` knows the tokens by. */
1031
+ provider: string;
1032
+ /** Where the visitor's browser is sent: the authorization server's `/authorize`, as the public reaches it. */
1033
+ authorizeUrl: string;
1034
+ /** Where this server registers itself and redeems codes — reachable from here, which may be a private address. */
1035
+ registerUrl: string;
1036
+ tokenUrl: string;
1037
+ /** What to ask for, for the space being signed into. */
1038
+ scope: (spaceId: number) => string;
1039
+ /** Where the flow answers. Default `/auth/sign-in`; the authorization server sends people back to `<path>/callback`. */
1040
+ path?: string;
1041
+ };
878
1042
  export type SSRPageServerConfig = SSRServerConfig & {
879
1043
  adapters: SSRPageAdapters;
880
1044
  };
@@ -961,8 +1125,15 @@ export type OAuthAdapters = {
961
1125
  * first visit.
962
1126
  */
963
1127
  identify: (req: SSRRequest) => Promise<OAuthUser | undefined>;
964
- /** What this user may grant access to. An empty list ends the flow with `access_denied`. */
965
- grantTargets: (user: OAuthUser) => Promise<OAuthGrantTarget[]>;
1128
+ /**
1129
+ * What this user may grant access to. An empty list ends the flow with `access_denied`.
1130
+ *
1131
+ * `request.scope` is what the client asked for, so one deployment can offer different choices to different
1132
+ * clients — a native client signing in as the person, and the same client asking which space to work in.
1133
+ */
1134
+ grantTargets: (user: OAuthUser, request: {
1135
+ scope?: string;
1136
+ }) => Promise<OAuthGrantTarget[]>;
966
1137
  /**
967
1138
  * End whatever session {@link OAuthAdapters.identify} was reading, so the person can connect as somebody else.
968
1139
  *
@@ -974,13 +1145,53 @@ export type OAuthAdapters = {
974
1145
  * that does not mean abandoning the connection and starting over from the host.
975
1146
  */
976
1147
  signOut?: (req: SSRRequest, res: SSRResponseHelpers) => void | Promise<void>;
977
- /** Mint the bearer the client will send on every MCP request. Return undefined to deny the grant. */
978
- issueToken: (user: OAuthUser, target: OAuthGrantTarget) => Promise<{
1148
+ /** Mint the bearer the client will send on every request. Return undefined to deny the grant. */
1149
+ issueToken: (user: OAuthUser, target: OAuthGrantTarget, context: OAuthIssueContext) => Promise<{
979
1150
  token: string;
980
1151
  expiresInSeconds?: number;
981
1152
  } | undefined>;
1153
+ /**
1154
+ * End a credential {@link OAuthAdapters.issueToken} minted, when its grant is revoked (RFC 7009).
1155
+ *
1156
+ * Optional, for a credential that ends on its own. Without it, revoking a grant stops it being RENEWED, and what
1157
+ * was already issued keeps working until it expires — which a person who just signed a device out reads as the
1158
+ * sign-out not having happened, because the device is still there in their list.
1159
+ */
1160
+ revokeToken?: (credential: string) => Promise<void>;
982
1161
  store: OAuthStore;
983
1162
  };
1163
+ /**
1164
+ * Who a credential is being issued to, beyond the person: which application, from where, and — on a renewal — which
1165
+ * credential it takes the place of.
1166
+ *
1167
+ * This is what lets a deployment tell its user WHICH of their devices a credential lives on. The application names
1168
+ * itself when it registers (RFC 7591 `client_name`, `software_id`); the request is the one the credential is being
1169
+ * issued on — at consent, the person's browser, which for a loopback client is the same machine.
1170
+ */
1171
+ export type OAuthIssueContext = {
1172
+ client: {
1173
+ clientId: string;
1174
+ /** What the application registered as: `Plitzi CLI on carlos-mbp`, `Claude`. */
1175
+ name: string;
1176
+ /** RFC 7591 `software_id`, when it sent one: a stable name for the SOFTWARE, the same on every machine. */
1177
+ softwareId?: string;
1178
+ };
1179
+ request?: {
1180
+ userAgent?: string;
1181
+ ip?: string;
1182
+ };
1183
+ /**
1184
+ * Where the code of THIS grant is sent: the `redirect_uri` of the authorization request, at consent. A deployment
1185
+ * whose credential is only good at certain addresses checks it here — registering a client is open to anybody, and
1186
+ * the address it names is the one thing that says who will receive what the person agreed to. Absent on a renewal.
1187
+ */
1188
+ redirectUri?: string;
1189
+ /**
1190
+ * The credential this grant last issued, on a renewal. A deployment that keeps a row per credential updates that
1191
+ * row rather than adding one, so a device renewing every hour stays one device.
1192
+ */
1193
+ replaces?: string;
1194
+ };
984
1195
  /** A connection a visitor may take WITHOUT signing in, for a server whose public surface needs no identity — the
985
1196
  * MCP App, the tool and resource listings, the guide. The consent screen offers it as a second button beside the
986
1197
  * sign-in, and the grant is whatever `target` grants: point it at a target that carries no space, never at one
@@ -1043,6 +1254,21 @@ export type OAuthConsentView = {
1043
1254
  canSwitchUser?: boolean;
1044
1255
  /** A message to show the user. */
1045
1256
  error?: string;
1257
+ /**
1258
+ * Who is asking, and where the grant goes if the person says yes.
1259
+ *
1260
+ * Anybody can register a client, call it anything and send somebody this screen on the deployment's own domain, so
1261
+ * the name alone proves nothing. The host the code is sent back to is the one fact the requester cannot choose
1262
+ * freely, and it is what tells "the app I just opened" apart from a stranger's server.
1263
+ */
1264
+ client: {
1265
+ /** What the client registered itself as. Chosen by the client, so it is shown as a claim. */
1266
+ name: string;
1267
+ /** The host of the `redirect_uri` the grant is delivered to. */
1268
+ redirectHost: string;
1269
+ /** The grant goes back to an app listening on this computer (RFC 8252 loopback), not to a server. */
1270
+ loopback: boolean;
1271
+ };
1046
1272
  branding: OAuthBranding;
1047
1273
  };
1048
1274
  /** OAuth 2.1 authorization for the MCP server (RFC 9728 discovery + RFC 7591 dynamic client registration +
@@ -1091,6 +1317,15 @@ export type OAuthConfig = {
1091
1317
  * holds, and wrapping it costs a store read on every request and gives a second thing to revoke.
1092
1318
  */
1093
1319
  directTokens?: boolean;
1320
+ /**
1321
+ * Accept only loopback `redirect_uri`s (`http://127.0.0.1:<port>/…`, RFC 8252 §7.3), at registration and again at
1322
+ * `/authorize`.
1323
+ *
1324
+ * Turn it on when every client is a native app on the person's own machine — a CLI, a desktop app — and above all
1325
+ * with {@link directTokens}, where the grant IS the person's session. Registration is open to anybody, so with https
1326
+ * redirects allowed a stranger's server can register, send somebody the link, and collect what they approve.
1327
+ */
1328
+ loopbackRedirectsOnly?: boolean;
1094
1329
  };
1095
1330
  /** A short-TTL, one-shot store for unsaved draft offline-data behind a preview token. The SDK ships an
1096
1331
  * in-memory default (fine for a single replica); a multi-replica deployment injects a shared (e.g. Redis)
@@ -1107,11 +1342,15 @@ export type OAuthConfig = {
1107
1342
  export type DraftPutOptions = {
1108
1343
  ttlMs: number;
1109
1344
  reusable?: boolean;
1345
+ /** The space the draft was made from. It is only ever rendered for that space. */
1346
+ spaceId: number;
1110
1347
  };
1111
1348
  /** A stashed draft, and whether the read that resolved it left it there. */
1112
1349
  export type DraftEntry = {
1113
1350
  data: OfflineDataRaw;
1114
1351
  reusable: boolean;
1352
+ /** The space the draft was made from — see {@link DraftPutOptions.spaceId}. */
1353
+ spaceId: number;
1115
1354
  };
1116
1355
  export type DraftStore = {
1117
1356
  put: (token: string, data: OfflineDataRaw, options: DraftPutOptions) => void | Promise<void>;
@@ -1133,7 +1372,12 @@ export type SSRPreviewConfig = {
1133
1372
  enabled?: boolean;
1134
1373
  /** Internal endpoint path that mints a preview token. Default '/__preview'. */
1135
1374
  path?: string;
1136
- /** Shared secret required in the `x-preview-secret` header; requests without it are rejected. */
1375
+ /**
1376
+ * Shared secret required in the `x-preview-secret` header; requests without it are rejected.
1377
+ *
1378
+ * Required for the endpoint to answer at all: the page server that hosts it is the one the public reaches, so an
1379
+ * enabled endpoint with no secret refuses every request rather than serving anyone.
1380
+ */
1137
1381
  secret?: string;
1138
1382
  /** One-shot token time-to-live in milliseconds. Default 60000. */
1139
1383
  ttlMs?: number;
@@ -44,6 +44,59 @@ export type SpaceCredential = {
44
44
  createdAt: number;
45
45
  updatedAt: number;
46
46
  };
47
+ /**
48
+ * A person given one of the space's visitor roles (`settings.visitorRoles`), by email. `claimed` says whether an
49
+ * account has taken it yet: a role given to an address waits for somebody to sign in with it, verified.
50
+ */
51
+ export type SpaceVisitor = {
52
+ id: number;
53
+ email: string;
54
+ role: string;
55
+ claimed: boolean;
56
+ createdAt: number;
57
+ updatedAt: number;
58
+ };
59
+ /** One environment's runtime — the space's own server code run beside the platform — and how it last was. */
60
+ export type SpaceRuntimeEnvironment = {
61
+ environment: string;
62
+ /** 0 for the draft. */
63
+ revision: number;
64
+ /** The packed code it runs, by what its bytes are. */
65
+ digest: string;
66
+ status: 'waiting' | 'starting' | 'ready' | 'failed' | 'stopping' | 'stopped';
67
+ /** Why it is not running, for whoever manages the space. */
68
+ error: string | null;
69
+ /** Why it is kept stopped: `idle` (unused for too long) or `manual`. */
70
+ stoppedReason: 'idle' | 'manual' | null;
71
+ /** When a running one stops for being unused, unless something uses it before — unix seconds. */
72
+ idleStopsAt: number | null;
73
+ /** The paths of the space it answers itself (`/mcp`). */
74
+ endpoints: string[];
75
+ /** Its tasks, as flows name them (`board.create`). */
76
+ tasks: string[];
77
+ startedAt: number | null;
78
+ /** The size it runs at — or will start at — by name (`SpaceRuntimeSizeOption['name']`). */
79
+ size: string;
80
+ };
81
+ /** A size a runtime may run at: what its pod may spend, and whether the space's plan includes it. */
82
+ export type SpaceRuntimeSizeOption = {
83
+ name: string;
84
+ label: string;
85
+ /** As Kubernetes reads it: `250m` is a quarter of a core. */
86
+ cpu: string;
87
+ /** As Kubernetes reads it: `256Mi`. */
88
+ memory: string;
89
+ included: boolean;
90
+ };
91
+ /** A space's runtime: every environment's, and the names of the variables it starts with — never their values. */
92
+ export type SpaceRuntime = {
93
+ environments: SpaceRuntimeEnvironment[];
94
+ variables: string[];
95
+ /** Every size there is, smallest first. */
96
+ sizes: SpaceRuntimeSizeOption[];
97
+ /** How long a runtime may go unused before it is stopped; 0 when the platform never stops one. */
98
+ idleMinutes: number;
99
+ };
47
100
  export type SpaceDeployment = {
48
101
  id: number;
49
102
  environment: Environment;
@@ -4,4 +4,10 @@ export type RuntimeStateInstance = {
4
4
  setState: (value: RuntimeState | ((prev: RuntimeState) => RuntimeState)) => void;
5
5
  setStateByKey: (key: string, value: unknown) => void;
6
6
  clearState: () => void;
7
+ /**
8
+ * Called with the whole state after every change to it, until the returned function is called. What a host or a
9
+ * plugin that keeps the state somewhere of its own — a store, a URL, an analytics call — listens to instead of
10
+ * polling `state`.
11
+ */
12
+ subscribe: (listener: (state: RuntimeState) => void) => () => void;
7
13
  };