@synap-core/sdk 1.4.0 → 1.5.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.
Files changed (50) hide show
  1. package/CHANGELOG.md +133 -0
  2. package/README.md +136 -10
  3. package/dist/{chunk-J7XHAAFJ.js → chunk-UK2U6SMA.js} +14 -2
  4. package/dist/chunk-UK2U6SMA.js.map +1 -0
  5. package/dist/{client-C5sF20f1.d.cts → client-B50KC2aJ.d.cts} +14 -9
  6. package/dist/{client-C5sF20f1.d.ts → client-B50KC2aJ.d.ts} +14 -9
  7. package/dist/connect.cjs +412 -64
  8. package/dist/connect.cjs.map +1 -1
  9. package/dist/connect.d.cts +400 -32
  10. package/dist/connect.d.ts +400 -32
  11. package/dist/connect.js +407 -65
  12. package/dist/connect.js.map +1 -1
  13. package/dist/public.cjs +9 -2
  14. package/dist/public.cjs.map +1 -1
  15. package/dist/public.d.cts +19 -4
  16. package/dist/public.d.ts +19 -4
  17. package/dist/public.js +8 -2
  18. package/dist/public.js.map +1 -1
  19. package/dist/testing.cjs +234 -12
  20. package/dist/testing.cjs.map +1 -1
  21. package/dist/testing.d.cts +122 -27
  22. package/dist/testing.d.ts +122 -27
  23. package/dist/testing.js +230 -12
  24. package/dist/testing.js.map +1 -1
  25. package/dist/{types-C2KGNXEn.d.cts → types-DZYNBCq7.d.cts} +28 -5
  26. package/dist/{types-C2KGNXEn.d.ts → types-DZYNBCq7.d.ts} +28 -5
  27. package/package.json +30 -6
  28. package/src/connect/auth.ts +156 -27
  29. package/src/connect/client.ts +374 -34
  30. package/src/connect/cloud.ts +14 -10
  31. package/src/connect/discovery.ts +66 -32
  32. package/src/connect/encoding.ts +1 -1
  33. package/src/connect/errors.ts +7 -0
  34. package/src/connect/flow.ts +42 -14
  35. package/src/connect/http.ts +42 -0
  36. package/src/connect/hub-types.ts +254 -0
  37. package/src/connect/index.ts +60 -42
  38. package/src/connect/rules.ts +18 -0
  39. package/src/connect/store.ts +9 -5
  40. package/src/connect/types.ts +28 -4
  41. package/src/public/client.ts +14 -2
  42. package/src/public/safe-markdown.ts +13 -0
  43. package/src/public/share-model.ts +6 -2
  44. package/src/public/site-model.ts +5 -3
  45. package/src/testing/auth-server.ts +239 -14
  46. package/src/testing/cloud.ts +3 -4
  47. package/src/testing/fixtures.ts +26 -0
  48. package/src/testing/index.ts +8 -6
  49. package/src/testing/seed.ts +120 -0
  50. package/dist/chunk-J7XHAAFJ.js.map +0 -1
@@ -1,5 +1,5 @@
1
- import { P as PublicForm, g as PublicShare, e as PublicRecord } from './client-C5sF20f1.cjs';
2
- import { P as PodGrant, a as PodUser, C as ClientMetadataDocument } from './types-C2KGNXEn.cjs';
1
+ import { P as PublicForm, h as PublicShare, f as PublicRecord } from './client-B50KC2aJ.cjs';
2
+ import { P as PodGrant, a as PodUser, b as PodActsAs, C as ClientMetadataDocument } from './types-DZYNBCq7.cjs';
3
3
 
4
4
  /**
5
5
  * Demo data for the mock pod. Shapes are the `@synap-core/sdk/public` wire
@@ -8,6 +8,12 @@ import { P as PodGrant, a as PodUser, C as ClientMetadataDocument } from './type
8
8
 
9
9
  declare const MOCK_FORM: PublicForm;
10
10
  declare const MOCK_SHARE: PublicShare;
11
+ /**
12
+ * A published HTML document (an estimate), as the pod serves an `html` body: a
13
+ * page renders it only inside `<iframe sandbox="" srcdoc>`, so the script below
14
+ * never runs.
15
+ */
16
+ declare const MOCK_HTML_SHARE: PublicShare;
11
17
  /** One collection of a mock site: its door config and its live records. */
12
18
  interface MockCollection {
13
19
  /** Default sort keys (`-` = descending); also the sort keys the door accepts. */
@@ -29,6 +35,90 @@ interface MockSite {
29
35
  */
30
36
  declare const MOCK_SITE: MockSite;
31
37
 
38
+ /**
39
+ * The mock pod's data as ONE JSON-serialisable shape, so an app's mock mode,
40
+ * smoke and screenshots replay a recorded snapshot (one file) instead of
41
+ * fixtures built in app code:
42
+ *
43
+ * import { readFileSync } from "node:fs";
44
+ * const seed = parseMockPodSeed(readFileSync("mock/pod-seed.json", "utf8"));
45
+ * const pod = createMockAuthServer({ seed });
46
+ *
47
+ * Rows are the pod's wire shapes (see `@synap-core/sdk/connect` hub-types):
48
+ * `entities` as `GET /entities` answers them, `sessions` as `GET
49
+ * /focus-sessions` rows (missing columns get the pod's defaults), `documents`
50
+ * as `GET /documents/:id` (`sections` and `diagnostics` answered empty),
51
+ * `relations` as graph edges for `GET /entities/:id/connections`, `proposals`
52
+ * as `GET /proposals?view=basic` rows, `spaces` name each granted space's
53
+ * template (`synap_grant[].templateSlug` on the token response).
54
+ */
55
+
56
+ interface MockSeedEntity {
57
+ id: string;
58
+ profileSlug?: string;
59
+ workspaceId?: string | null;
60
+ title?: string | null;
61
+ properties?: Record<string, unknown>;
62
+ [key: string]: unknown;
63
+ }
64
+ interface MockSeedSession {
65
+ id: string;
66
+ workspaceId?: string | null;
67
+ projectId?: string | null;
68
+ goal?: string;
69
+ status?: string;
70
+ /** Slots; `owner: "human"` ones are what waits on the person. */
71
+ expectedOutputs?: Array<Record<string, unknown>>;
72
+ /** The entity it is about: listed among that entity's connections. */
73
+ subjectEntityId?: string | null;
74
+ /** ISO 8601; the list is newest first by it. */
75
+ startedAt?: string;
76
+ [key: string]: unknown;
77
+ }
78
+ interface MockSeedDocument {
79
+ id: string;
80
+ title: string;
81
+ content: string;
82
+ type?: string;
83
+ language?: string | null;
84
+ workspaceId?: string | null;
85
+ revision?: number;
86
+ version?: number;
87
+ createdAt?: string;
88
+ updatedAt?: string;
89
+ }
90
+ interface MockSeedRelation {
91
+ id: string;
92
+ sourceEntityId: string;
93
+ targetEntityId: string;
94
+ type: string;
95
+ createdAt?: string;
96
+ }
97
+ interface MockSeedSpace {
98
+ id: string;
99
+ name: string;
100
+ /** The template it came from (e.g. `content-os`); absent = made by hand. */
101
+ templateSlug?: string;
102
+ }
103
+ interface MockPodSeed {
104
+ entities?: MockSeedEntity[];
105
+ sessions?: MockSeedSession[];
106
+ documents?: MockSeedDocument[];
107
+ relations?: MockSeedRelation[];
108
+ /** Missing fields default to a pending `create` of an `entity`, with null ids and the seed's load time. */
109
+ proposals?: Array<Partial<MockProposal> & {
110
+ id: string;
111
+ }>;
112
+ spaces?: MockSeedSpace[];
113
+ }
114
+ /**
115
+ * Read a seed (JSON text or an already-parsed value) and check its shape:
116
+ * every collection optional, each an array of objects carrying its required
117
+ * string fields; unknown top-level keys are refused (a typo would otherwise
118
+ * seed nothing). Throws `TypeError` naming the first bad path.
119
+ */
120
+ declare function parseMockPodSeed(input: string | unknown): MockPodSeed;
121
+
32
122
  /** A placeholder pod origin; never contacted. */
33
123
  declare const MOCK_AUTH_ISSUER = "https://pod.mock-synap.test";
34
124
  declare const MOCK_GRANT: PodGrant[];
@@ -36,7 +126,7 @@ declare const MOCK_USER: PodUser;
36
126
  type MockHubFailure = "rate_limited" | "forbidden" | "door_unsupported" | "unreachable" | "server" | "unavailable";
37
127
  interface MockAuthServerOptions {
38
128
  issuer?: string;
39
- /** Issue rotating refresh tokens (PB3). Default true; false = a pod before PB3. */
129
+ /** Issue rotating refresh tokens. Default true; false = a pod without refresh tokens. */
40
130
  refresh?: boolean;
41
131
  /** Default 3600 (the pod's 1 h). */
42
132
  accessTtlSec?: number;
@@ -44,7 +134,7 @@ interface MockAuthServerOptions {
44
134
  refreshIdleSec?: number;
45
135
  /** Send `refresh_token_expires_in` with each refresh token. Default false (the pod does not say). */
46
136
  advertiseRefreshExpiry?: boolean;
47
- /** The reuse grace, seconds (PB3b). Default 30 (the pod's); 0 = off (a pod before PB3b). */
137
+ /** The reuse grace, seconds. Default 30 (the pod's); 0 = off (a pod without the grace). */
48
138
  refreshGraceSec?: number;
49
139
  /**
50
140
  * `synap_app` on token responses: the connection's id and its page on the
@@ -60,8 +150,22 @@ interface MockAuthServerOptions {
60
150
  user?: PodUser;
61
151
  /** Override or remove (undefined) metadata fields: a pod too old, a lying issuer. */
62
152
  metadata?: Record<string, unknown>;
63
- /** Hub writes: "proposed" (ask-first, the default for an app) or "applied". */
153
+ /**
154
+ * Hub writes: "proposed" (ask-first, the default for an agent token) or
155
+ * "applied" (the default for `actsAs: "person"`).
156
+ */
64
157
  writeMode?: "proposed" | "applied";
158
+ /**
159
+ * `synap_acts_as` on token responses. Omitted = not sent (a pod that does
160
+ * not name it; the SDK reads an agent connection).
161
+ */
162
+ actsAs?: PodActsAs;
163
+ /**
164
+ * The pod's data as one JSON shape (`parseMockPodSeed`). `seed.entities` come
165
+ * before `entities`; `seed.spaces` put a `templateSlug` on the grant rows of
166
+ * those spaces.
167
+ */
168
+ seed?: MockPodSeed;
65
169
  /** Hub paths (after /api/hub) that answer one failure. */
66
170
  failures?: Record<string, MockHubFailure>;
67
171
  now?: () => number;
@@ -113,8 +217,10 @@ interface MockAuthServer {
113
217
  path: string;
114
218
  body: unknown;
115
219
  }>;
116
- /** Proposals filed by proposed writes, in order. */
220
+ /** Proposals: the seeded ones, then those filed by proposed writes, in order. */
117
221
  proposals: MockProposal[];
222
+ /** Proposals approved through `POST /proposals/:id/approve`, in order. */
223
+ approvals: string[];
118
224
  /** The person approved or rejected one: it leaves the pending list. */
119
225
  settleProposal(id: string, status: "approved" | "rejected"): void;
120
226
  /** Another instance of the app rotated `token` (its own refresh): returns the pair the pod answered it. */
@@ -135,30 +241,18 @@ interface MockAuthServer {
135
241
  reuses: number;
136
242
  /** The person revoked the app: every token stops working. */
137
243
  revokeAll(): void;
244
+ /**
245
+ * The live access keys stop working, the refresh tokens do not: what a
246
+ * narrow (the slot's key is revoked at once) or a pod-side "Revoke key"
247
+ * does. The next refresh mints a new key.
248
+ */
249
+ revokeAccessKeys(): void;
138
250
  /** Live (unrevoked) refresh tokens. */
139
251
  liveRefreshTokens(): string[];
140
252
  reset(): void;
141
253
  }
142
254
  declare function createMockAuthServer(options?: MockAuthServerOptions): MockAuthServer;
143
255
 
144
- /**
145
- * A mock Synap Cloud pod chooser (Control Plane `GET /connect/pod`, wave C1)
146
- * for "Continue with Synap Cloud" tests and a kit's mock mode. No network:
147
- * `choose()` stands in for the person signing in to the CP and picking a pod.
148
- *
149
- * Wire behaviour mirrors the CP route (doc 18 §1.1): it accepts only
150
- * `client_id` (an https CIMD URL; http on loopback only with
151
- * `allowInsecureLoopback`, for a kit's mock mode on http://localhost) and
152
- * `state` (`^[A-Za-z0-9._~-]{16,256}$`),
153
- * takes the return URL from the app's client metadata (`initiate_login_uri`),
154
- * never from the query, and answers `<initiate_login_uri>?iss=<pod issuer>&state=<state>`.
155
- * It never sees a code or a token.
156
- *
157
- * const cloud = createMockCloud();
158
- * createPodAppAuth({ ...config, cloudUrl: cloud.url });
159
- * cloud.choose(location, { pod: mockPod.issuer, metadata: auth.metadata }) → the app's return URL
160
- */
161
-
162
256
  /** A placeholder Control Plane origin; never contacted. */
163
257
  declare const MOCK_CLOUD_URL = "https://cp.mock-synap.test";
164
258
  interface MockCloud {
@@ -198,12 +292,12 @@ declare function createMockCloud(options?: {
198
292
  * `credentials: "include"` request is refused (it rejects, as a CORS failure
199
293
  * does); with `{ browser: true }` a non-safelisted request header is too.
200
294
  *
201
- * tokens MOCK_TOKENS.form / .share / .site the demo form, share and site
295
+ * tokens MOCK_TOKENS.form / .share / .htmlShare / .site the demo form, shares (markdown, html) and site
202
296
  * tokens MOCK_FAILURE_TOKENS.* one failure on every door
203
297
  * anything else the uniform 404
204
298
  *
205
299
  * Pod-app sign-in (`@synap-core/sdk/connect`): `createMockAuthServer()`, see
206
- * ./auth-server.ts; Synap Cloud's pod chooser: `createMockCloud()`, ./cloud.ts.
300
+ * ./auth-server.ts, seeded from one JSON shape (`parseMockPodSeed`, ./seed.ts); Synap Cloud's pod chooser: `createMockCloud()`, ./cloud.ts.
207
301
  */
208
302
 
209
303
  /** A placeholder origin; never contacted. */
@@ -211,6 +305,7 @@ declare const MOCK_POD_URL = "https://mock.synap.invalid";
211
305
  declare const MOCK_TOKENS: {
212
306
  readonly form: "demo-form";
213
307
  readonly share: "demo";
308
+ readonly htmlShare: "demo-html";
214
309
  readonly site: "demo-site";
215
310
  };
216
311
  /** The `Retry-After` the `rateLimitedRetryAfter` token sends. */
@@ -266,4 +361,4 @@ interface MockPod {
266
361
  }
267
362
  declare function createMockPod(options?: MockPodOptions): MockPod;
268
363
 
269
- export { type AuthorizeDecision, MOCK_APP, MOCK_APP_AGENT_ID, MOCK_AUTH_ISSUER, MOCK_CLOUD_URL, MOCK_FAILURE_TOKENS, MOCK_FORM, MOCK_GRANT, MOCK_POD_URL, MOCK_RETRY_AFTER_SEC, MOCK_SHARE, MOCK_SITE, MOCK_TOKENS, MOCK_USER, type MockAuthRequest, type MockAuthServer, type MockAuthServerOptions, type MockCloud, type MockCollection, type MockHubFailure, type MockPod, type MockPodOptions, type MockProposal, type MockRequest, type MockSite, type MockSubmission, createMockAuthServer, createMockCloud, createMockPod };
364
+ export { type AuthorizeDecision, MOCK_APP, MOCK_APP_AGENT_ID, MOCK_AUTH_ISSUER, MOCK_CLOUD_URL, MOCK_FAILURE_TOKENS, MOCK_FORM, MOCK_GRANT, MOCK_HTML_SHARE, MOCK_POD_URL, MOCK_RETRY_AFTER_SEC, MOCK_SHARE, MOCK_SITE, MOCK_TOKENS, MOCK_USER, type MockAuthRequest, type MockAuthServer, type MockAuthServerOptions, type MockCloud, type MockCollection, type MockHubFailure, type MockPod, type MockPodOptions, type MockPodSeed, type MockProposal, type MockRequest, type MockSeedDocument, type MockSeedEntity, type MockSeedRelation, type MockSeedSession, type MockSeedSpace, type MockSite, type MockSubmission, createMockAuthServer, createMockCloud, createMockPod, parseMockPodSeed };
package/dist/testing.d.ts CHANGED
@@ -1,5 +1,5 @@
1
- import { P as PublicForm, g as PublicShare, e as PublicRecord } from './client-C5sF20f1.js';
2
- import { P as PodGrant, a as PodUser, C as ClientMetadataDocument } from './types-C2KGNXEn.js';
1
+ import { P as PublicForm, h as PublicShare, f as PublicRecord } from './client-B50KC2aJ.js';
2
+ import { P as PodGrant, a as PodUser, b as PodActsAs, C as ClientMetadataDocument } from './types-DZYNBCq7.js';
3
3
 
4
4
  /**
5
5
  * Demo data for the mock pod. Shapes are the `@synap-core/sdk/public` wire
@@ -8,6 +8,12 @@ import { P as PodGrant, a as PodUser, C as ClientMetadataDocument } from './type
8
8
 
9
9
  declare const MOCK_FORM: PublicForm;
10
10
  declare const MOCK_SHARE: PublicShare;
11
+ /**
12
+ * A published HTML document (an estimate), as the pod serves an `html` body: a
13
+ * page renders it only inside `<iframe sandbox="" srcdoc>`, so the script below
14
+ * never runs.
15
+ */
16
+ declare const MOCK_HTML_SHARE: PublicShare;
11
17
  /** One collection of a mock site: its door config and its live records. */
12
18
  interface MockCollection {
13
19
  /** Default sort keys (`-` = descending); also the sort keys the door accepts. */
@@ -29,6 +35,90 @@ interface MockSite {
29
35
  */
30
36
  declare const MOCK_SITE: MockSite;
31
37
 
38
+ /**
39
+ * The mock pod's data as ONE JSON-serialisable shape, so an app's mock mode,
40
+ * smoke and screenshots replay a recorded snapshot (one file) instead of
41
+ * fixtures built in app code:
42
+ *
43
+ * import { readFileSync } from "node:fs";
44
+ * const seed = parseMockPodSeed(readFileSync("mock/pod-seed.json", "utf8"));
45
+ * const pod = createMockAuthServer({ seed });
46
+ *
47
+ * Rows are the pod's wire shapes (see `@synap-core/sdk/connect` hub-types):
48
+ * `entities` as `GET /entities` answers them, `sessions` as `GET
49
+ * /focus-sessions` rows (missing columns get the pod's defaults), `documents`
50
+ * as `GET /documents/:id` (`sections` and `diagnostics` answered empty),
51
+ * `relations` as graph edges for `GET /entities/:id/connections`, `proposals`
52
+ * as `GET /proposals?view=basic` rows, `spaces` name each granted space's
53
+ * template (`synap_grant[].templateSlug` on the token response).
54
+ */
55
+
56
+ interface MockSeedEntity {
57
+ id: string;
58
+ profileSlug?: string;
59
+ workspaceId?: string | null;
60
+ title?: string | null;
61
+ properties?: Record<string, unknown>;
62
+ [key: string]: unknown;
63
+ }
64
+ interface MockSeedSession {
65
+ id: string;
66
+ workspaceId?: string | null;
67
+ projectId?: string | null;
68
+ goal?: string;
69
+ status?: string;
70
+ /** Slots; `owner: "human"` ones are what waits on the person. */
71
+ expectedOutputs?: Array<Record<string, unknown>>;
72
+ /** The entity it is about: listed among that entity's connections. */
73
+ subjectEntityId?: string | null;
74
+ /** ISO 8601; the list is newest first by it. */
75
+ startedAt?: string;
76
+ [key: string]: unknown;
77
+ }
78
+ interface MockSeedDocument {
79
+ id: string;
80
+ title: string;
81
+ content: string;
82
+ type?: string;
83
+ language?: string | null;
84
+ workspaceId?: string | null;
85
+ revision?: number;
86
+ version?: number;
87
+ createdAt?: string;
88
+ updatedAt?: string;
89
+ }
90
+ interface MockSeedRelation {
91
+ id: string;
92
+ sourceEntityId: string;
93
+ targetEntityId: string;
94
+ type: string;
95
+ createdAt?: string;
96
+ }
97
+ interface MockSeedSpace {
98
+ id: string;
99
+ name: string;
100
+ /** The template it came from (e.g. `content-os`); absent = made by hand. */
101
+ templateSlug?: string;
102
+ }
103
+ interface MockPodSeed {
104
+ entities?: MockSeedEntity[];
105
+ sessions?: MockSeedSession[];
106
+ documents?: MockSeedDocument[];
107
+ relations?: MockSeedRelation[];
108
+ /** Missing fields default to a pending `create` of an `entity`, with null ids and the seed's load time. */
109
+ proposals?: Array<Partial<MockProposal> & {
110
+ id: string;
111
+ }>;
112
+ spaces?: MockSeedSpace[];
113
+ }
114
+ /**
115
+ * Read a seed (JSON text or an already-parsed value) and check its shape:
116
+ * every collection optional, each an array of objects carrying its required
117
+ * string fields; unknown top-level keys are refused (a typo would otherwise
118
+ * seed nothing). Throws `TypeError` naming the first bad path.
119
+ */
120
+ declare function parseMockPodSeed(input: string | unknown): MockPodSeed;
121
+
32
122
  /** A placeholder pod origin; never contacted. */
33
123
  declare const MOCK_AUTH_ISSUER = "https://pod.mock-synap.test";
34
124
  declare const MOCK_GRANT: PodGrant[];
@@ -36,7 +126,7 @@ declare const MOCK_USER: PodUser;
36
126
  type MockHubFailure = "rate_limited" | "forbidden" | "door_unsupported" | "unreachable" | "server" | "unavailable";
37
127
  interface MockAuthServerOptions {
38
128
  issuer?: string;
39
- /** Issue rotating refresh tokens (PB3). Default true; false = a pod before PB3. */
129
+ /** Issue rotating refresh tokens. Default true; false = a pod without refresh tokens. */
40
130
  refresh?: boolean;
41
131
  /** Default 3600 (the pod's 1 h). */
42
132
  accessTtlSec?: number;
@@ -44,7 +134,7 @@ interface MockAuthServerOptions {
44
134
  refreshIdleSec?: number;
45
135
  /** Send `refresh_token_expires_in` with each refresh token. Default false (the pod does not say). */
46
136
  advertiseRefreshExpiry?: boolean;
47
- /** The reuse grace, seconds (PB3b). Default 30 (the pod's); 0 = off (a pod before PB3b). */
137
+ /** The reuse grace, seconds. Default 30 (the pod's); 0 = off (a pod without the grace). */
48
138
  refreshGraceSec?: number;
49
139
  /**
50
140
  * `synap_app` on token responses: the connection's id and its page on the
@@ -60,8 +150,22 @@ interface MockAuthServerOptions {
60
150
  user?: PodUser;
61
151
  /** Override or remove (undefined) metadata fields: a pod too old, a lying issuer. */
62
152
  metadata?: Record<string, unknown>;
63
- /** Hub writes: "proposed" (ask-first, the default for an app) or "applied". */
153
+ /**
154
+ * Hub writes: "proposed" (ask-first, the default for an agent token) or
155
+ * "applied" (the default for `actsAs: "person"`).
156
+ */
64
157
  writeMode?: "proposed" | "applied";
158
+ /**
159
+ * `synap_acts_as` on token responses. Omitted = not sent (a pod that does
160
+ * not name it; the SDK reads an agent connection).
161
+ */
162
+ actsAs?: PodActsAs;
163
+ /**
164
+ * The pod's data as one JSON shape (`parseMockPodSeed`). `seed.entities` come
165
+ * before `entities`; `seed.spaces` put a `templateSlug` on the grant rows of
166
+ * those spaces.
167
+ */
168
+ seed?: MockPodSeed;
65
169
  /** Hub paths (after /api/hub) that answer one failure. */
66
170
  failures?: Record<string, MockHubFailure>;
67
171
  now?: () => number;
@@ -113,8 +217,10 @@ interface MockAuthServer {
113
217
  path: string;
114
218
  body: unknown;
115
219
  }>;
116
- /** Proposals filed by proposed writes, in order. */
220
+ /** Proposals: the seeded ones, then those filed by proposed writes, in order. */
117
221
  proposals: MockProposal[];
222
+ /** Proposals approved through `POST /proposals/:id/approve`, in order. */
223
+ approvals: string[];
118
224
  /** The person approved or rejected one: it leaves the pending list. */
119
225
  settleProposal(id: string, status: "approved" | "rejected"): void;
120
226
  /** Another instance of the app rotated `token` (its own refresh): returns the pair the pod answered it. */
@@ -135,30 +241,18 @@ interface MockAuthServer {
135
241
  reuses: number;
136
242
  /** The person revoked the app: every token stops working. */
137
243
  revokeAll(): void;
244
+ /**
245
+ * The live access keys stop working, the refresh tokens do not: what a
246
+ * narrow (the slot's key is revoked at once) or a pod-side "Revoke key"
247
+ * does. The next refresh mints a new key.
248
+ */
249
+ revokeAccessKeys(): void;
138
250
  /** Live (unrevoked) refresh tokens. */
139
251
  liveRefreshTokens(): string[];
140
252
  reset(): void;
141
253
  }
142
254
  declare function createMockAuthServer(options?: MockAuthServerOptions): MockAuthServer;
143
255
 
144
- /**
145
- * A mock Synap Cloud pod chooser (Control Plane `GET /connect/pod`, wave C1)
146
- * for "Continue with Synap Cloud" tests and a kit's mock mode. No network:
147
- * `choose()` stands in for the person signing in to the CP and picking a pod.
148
- *
149
- * Wire behaviour mirrors the CP route (doc 18 §1.1): it accepts only
150
- * `client_id` (an https CIMD URL; http on loopback only with
151
- * `allowInsecureLoopback`, for a kit's mock mode on http://localhost) and
152
- * `state` (`^[A-Za-z0-9._~-]{16,256}$`),
153
- * takes the return URL from the app's client metadata (`initiate_login_uri`),
154
- * never from the query, and answers `<initiate_login_uri>?iss=<pod issuer>&state=<state>`.
155
- * It never sees a code or a token.
156
- *
157
- * const cloud = createMockCloud();
158
- * createPodAppAuth({ ...config, cloudUrl: cloud.url });
159
- * cloud.choose(location, { pod: mockPod.issuer, metadata: auth.metadata }) → the app's return URL
160
- */
161
-
162
256
  /** A placeholder Control Plane origin; never contacted. */
163
257
  declare const MOCK_CLOUD_URL = "https://cp.mock-synap.test";
164
258
  interface MockCloud {
@@ -198,12 +292,12 @@ declare function createMockCloud(options?: {
198
292
  * `credentials: "include"` request is refused (it rejects, as a CORS failure
199
293
  * does); with `{ browser: true }` a non-safelisted request header is too.
200
294
  *
201
- * tokens MOCK_TOKENS.form / .share / .site the demo form, share and site
295
+ * tokens MOCK_TOKENS.form / .share / .htmlShare / .site the demo form, shares (markdown, html) and site
202
296
  * tokens MOCK_FAILURE_TOKENS.* one failure on every door
203
297
  * anything else the uniform 404
204
298
  *
205
299
  * Pod-app sign-in (`@synap-core/sdk/connect`): `createMockAuthServer()`, see
206
- * ./auth-server.ts; Synap Cloud's pod chooser: `createMockCloud()`, ./cloud.ts.
300
+ * ./auth-server.ts, seeded from one JSON shape (`parseMockPodSeed`, ./seed.ts); Synap Cloud's pod chooser: `createMockCloud()`, ./cloud.ts.
207
301
  */
208
302
 
209
303
  /** A placeholder origin; never contacted. */
@@ -211,6 +305,7 @@ declare const MOCK_POD_URL = "https://mock.synap.invalid";
211
305
  declare const MOCK_TOKENS: {
212
306
  readonly form: "demo-form";
213
307
  readonly share: "demo";
308
+ readonly htmlShare: "demo-html";
214
309
  readonly site: "demo-site";
215
310
  };
216
311
  /** The `Retry-After` the `rateLimitedRetryAfter` token sends. */
@@ -266,4 +361,4 @@ interface MockPod {
266
361
  }
267
362
  declare function createMockPod(options?: MockPodOptions): MockPod;
268
363
 
269
- export { type AuthorizeDecision, MOCK_APP, MOCK_APP_AGENT_ID, MOCK_AUTH_ISSUER, MOCK_CLOUD_URL, MOCK_FAILURE_TOKENS, MOCK_FORM, MOCK_GRANT, MOCK_POD_URL, MOCK_RETRY_AFTER_SEC, MOCK_SHARE, MOCK_SITE, MOCK_TOKENS, MOCK_USER, type MockAuthRequest, type MockAuthServer, type MockAuthServerOptions, type MockCloud, type MockCollection, type MockHubFailure, type MockPod, type MockPodOptions, type MockProposal, type MockRequest, type MockSite, type MockSubmission, createMockAuthServer, createMockCloud, createMockPod };
364
+ export { type AuthorizeDecision, MOCK_APP, MOCK_APP_AGENT_ID, MOCK_AUTH_ISSUER, MOCK_CLOUD_URL, MOCK_FAILURE_TOKENS, MOCK_FORM, MOCK_GRANT, MOCK_HTML_SHARE, MOCK_POD_URL, MOCK_RETRY_AFTER_SEC, MOCK_SHARE, MOCK_SITE, MOCK_TOKENS, MOCK_USER, type MockAuthRequest, type MockAuthServer, type MockAuthServerOptions, type MockCloud, type MockCollection, type MockHubFailure, type MockPod, type MockPodOptions, type MockPodSeed, type MockProposal, type MockRequest, type MockSeedDocument, type MockSeedEntity, type MockSeedRelation, type MockSeedSession, type MockSeedSpace, type MockSite, type MockSubmission, createMockAuthServer, createMockCloud, createMockPod, parseMockPodSeed };