@hops-ops/distributed 4.9.0 → 4.11.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/README.md +89 -8
- package/dist/replica/distributed-replica/impl-protocol.d.ts +1 -0
- package/dist/replica/distributed-replica/impl-protocol.js +1 -0
- package/dist/replica/distributed-replica/impl.js +11 -0
- package/dist/replica/distributed-replica/watch.js +13 -1
- package/dist/replica/identity/codec.d.ts +1 -0
- package/dist/replica/identity/codec.js +16 -3
- package/dist/replica/index.d.ts +1 -1
- package/dist/replica/types.d.ts +42 -1
- package/dist/sveltekit/boundary-lifecycle.d.ts +37 -0
- package/dist/sveltekit/boundary-lifecycle.js +355 -0
- package/dist/sveltekit/boundary-variables.d.ts +57 -0
- package/dist/sveltekit/boundary-variables.js +294 -0
- package/dist/sveltekit/context.d.ts +3 -0
- package/dist/sveltekit/context.js +8 -0
- package/dist/sveltekit/index.d.ts +6 -3
- package/dist/sveltekit/index.js +5 -2
- package/dist/sveltekit/island-bindings.d.ts +17 -0
- package/dist/sveltekit/island-bindings.js +58 -0
- package/dist/sveltekit/islands/boundaries.d.ts +107 -0
- package/dist/sveltekit/islands/boundaries.js +788 -0
- package/dist/sveltekit/operation-identity.d.ts +4 -0
- package/dist/sveltekit/operation-identity.js +10 -0
- package/dist/sveltekit/replica.d.ts +24 -0
- package/dist/sveltekit/replica.js +72 -5
- package/dist/sveltekit/server-replica.d.ts +10 -26
- package/dist/sveltekit/server-replica.js +159 -132
- package/dist/sveltekit/vite.d.ts +10 -3
- package/dist/sveltekit/vite.js +310 -39
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -5,7 +5,7 @@ The generated, end-to-end typed client for
|
|
|
5
5
|
|
|
6
6
|
Rust table, relationship, role, and command definitions produce one authorized
|
|
7
7
|
client surface. `distributed client` combines that surface with application GraphQL
|
|
8
|
-
documents and emits typed operations, live companions,
|
|
8
|
+
documents and emits typed operations, live companions, island metadata, and
|
|
9
9
|
commands. This package executes those artifacts through one normalized,
|
|
10
10
|
causally consistent browser replica.
|
|
11
11
|
|
|
@@ -67,7 +67,7 @@ injects wire-only identity and revision fields, and emits:
|
|
|
67
67
|
- an exact typed operation and optional live companion;
|
|
68
68
|
- normalization, identity, relationship, filter, order, and pagination plans;
|
|
69
69
|
- the closed variable codec used before cache lookup or transport;
|
|
70
|
-
-
|
|
70
|
+
- framework-neutral island metadata plus an inspectable SvelteKit boundary plan;
|
|
71
71
|
- an SSR-safe SvelteKit wrapper with static operation bindings and tree-local
|
|
72
72
|
client/command access;
|
|
73
73
|
- a nested command tree with input defaults, optimistic effects, and causal
|
|
@@ -100,7 +100,10 @@ export const distributedClients = [
|
|
|
100
100
|
module: '$distributed',
|
|
101
101
|
manifest: { args: serviceManifestArgs },
|
|
102
102
|
surface: 'e2e-ui',
|
|
103
|
-
documents: [
|
|
103
|
+
documents: [
|
|
104
|
+
'src/routes/(app)/**/*.graphql',
|
|
105
|
+
'src/lib/components/**/*.graphql'
|
|
106
|
+
],
|
|
104
107
|
out: 'src/lib/generated/distributed'
|
|
105
108
|
},
|
|
106
109
|
{
|
|
@@ -128,6 +131,56 @@ keeps ordinary application documents out of the admin tree; each trust boundary
|
|
|
128
131
|
has its own Rust manifest entrypoint, generated directory, virtual module, and
|
|
129
132
|
request-local replica. A single-surface application can omit the second entry.
|
|
130
133
|
|
|
134
|
+
A component can own a sibling `Component.graphql` island. The adapter walks
|
|
135
|
+
static Svelte imports and promotes `@load` work to the nearest page/layout.
|
|
136
|
+
Route-local `+page.graphql` and `+layout.graphql` remain first-class. When a
|
|
137
|
+
surface needs its own authorization-specific copy, use a qualified route
|
|
138
|
+
document such as `+layout.public.graphql`; it still belongs to that layout.
|
|
139
|
+
|
|
140
|
+
Put stable values in GraphQL itself:
|
|
141
|
+
|
|
142
|
+
```graphql
|
|
143
|
+
query ChatMessages(
|
|
144
|
+
$limit: Int! = 25
|
|
145
|
+
$offset: Int! = 0
|
|
146
|
+
) @load @live {
|
|
147
|
+
chat_messages(limit: $limit, offset: $offset) { message_id body }
|
|
148
|
+
}
|
|
149
|
+
```
|
|
150
|
+
|
|
151
|
+
The generated variable properties are optional, while the compiler-owned codec
|
|
152
|
+
canonicalizes the defaults before cache identity, SSR, live continuation, or
|
|
153
|
+
transport. An explicit `ChatMessages.use({ limit: 50, offset: 0 })` overrides
|
|
154
|
+
them; `ChatMessages.use()` uses the exact defaults.
|
|
155
|
+
|
|
156
|
+
Same-name route parameters are inferred. For external values, add one bounded
|
|
157
|
+
sidecar beside the document rather than putting screen behavior in
|
|
158
|
+
`distributed.config.js`:
|
|
159
|
+
|
|
160
|
+
```js
|
|
161
|
+
// SearchResults.graphql.bindings.js
|
|
162
|
+
import {
|
|
163
|
+
defineGraphqlIslandBindings,
|
|
164
|
+
forwardedProp,
|
|
165
|
+
searchParam,
|
|
166
|
+
sessionClaim
|
|
167
|
+
} from '@hops-ops/distributed/sveltekit';
|
|
168
|
+
|
|
169
|
+
export default defineGraphqlIslandBindings({
|
|
170
|
+
query: searchParam('q'),
|
|
171
|
+
viewerId: sessionClaim('user', 'id'),
|
|
172
|
+
filters: forwardedProp('filters')
|
|
173
|
+
});
|
|
174
|
+
```
|
|
175
|
+
|
|
176
|
+
The helper rejects unsafe shapes, generation checks the keys against the
|
|
177
|
+
operation, and the same binding is reused by SSR, hover prefetch, navigation,
|
|
178
|
+
hydration, and live work. Resolution precedence is explicit call variables,
|
|
179
|
+
then sidecar/route sources, then GraphQL defaults. A non-null variable without
|
|
180
|
+
any of those sources fails generation before transport. Central `boundaries`
|
|
181
|
+
registrations remain an explicit-placement escape hatch and cannot be combined
|
|
182
|
+
with a sidecar for the same operation.
|
|
183
|
+
|
|
131
184
|
The Vite integration runs `distributed client` at startup/build, watches GraphQL
|
|
132
185
|
documents, stages all surfaces, commits a rollback-capable multi-output
|
|
133
186
|
transaction, then triggers one reload. It exposes the generated Svelte wrapper
|
|
@@ -194,11 +247,11 @@ import {
|
|
|
194
247
|
createDistributedSvelteKitServer
|
|
195
248
|
} from '@hops-ops/distributed/sveltekit';
|
|
196
249
|
import {
|
|
197
|
-
|
|
250
|
+
DISTRIBUTED_BOUNDARY_OPERATIONS
|
|
198
251
|
} from '$distributed';
|
|
199
252
|
|
|
200
253
|
const distributed = createDistributedSvelteKitServer({
|
|
201
|
-
|
|
254
|
+
boundaries: DISTRIBUTED_BOUNDARY_OPERATIONS,
|
|
202
255
|
getSession: ({ locals }) => locals.auth(),
|
|
203
256
|
getRole: (session) => roleFromSession(session)
|
|
204
257
|
});
|
|
@@ -212,15 +265,20 @@ authorization lifecycle. The generated module retains no client singleton:
|
|
|
212
265
|
```ts
|
|
213
266
|
// src/routes/+layout.svelte
|
|
214
267
|
import { browser } from '$app/environment';
|
|
268
|
+
import { page } from '$app/state';
|
|
215
269
|
import {
|
|
216
270
|
createPageDataSessionSource
|
|
217
271
|
} from '@hops-ops/distributed/sveltekit';
|
|
218
|
-
import {
|
|
272
|
+
import {
|
|
273
|
+
DISTRIBUTED_BOUNDARY_OPERATIONS,
|
|
274
|
+
provideDistributed
|
|
275
|
+
} from '$distributed';
|
|
219
276
|
|
|
220
277
|
let { data, children } = $props();
|
|
221
278
|
const pageData = createPageDataSessionSource(data);
|
|
222
279
|
|
|
223
280
|
const client = provideDistributed({
|
|
281
|
+
boundaries: DISTRIBUTED_BOUNDARY_OPERATIONS,
|
|
224
282
|
browser,
|
|
225
283
|
session: pageData.session,
|
|
226
284
|
...(data.distributed !== undefined &&
|
|
@@ -233,6 +291,26 @@ const client = provideDistributed({
|
|
|
233
291
|
});
|
|
234
292
|
|
|
235
293
|
$effect(() => pageData.set(data));
|
|
294
|
+
|
|
295
|
+
$effect(() => {
|
|
296
|
+
const retained = client.retainLocation(
|
|
297
|
+
{ id: 'active-page', pathname: page.url.pathname, kind: 'page' },
|
|
298
|
+
{
|
|
299
|
+
search: page.url.searchParams,
|
|
300
|
+
session: data.session,
|
|
301
|
+
props: data
|
|
302
|
+
}
|
|
303
|
+
);
|
|
304
|
+
return () => retained.release();
|
|
305
|
+
});
|
|
306
|
+
|
|
307
|
+
// A delegated link-hover handler can warm any generated target without an
|
|
308
|
+
// operation-name switch or a second variable map.
|
|
309
|
+
await client.prefetchLocation(target.pathname, {
|
|
310
|
+
search: target.searchParams,
|
|
311
|
+
session: data.session,
|
|
312
|
+
props: data
|
|
313
|
+
});
|
|
236
314
|
```
|
|
237
315
|
|
|
238
316
|
Route components import only their generated surface. Static operation wrappers
|
|
@@ -296,7 +374,10 @@ deduplicates work, and optionally maintains the generated live operation.
|
|
|
296
374
|
`read()` is side-effect-free. `dehydrate()` and `hydrate()` transfer confirmed
|
|
297
375
|
state without exposing a public storage schema. Cold `hydrate` seeds an empty
|
|
298
376
|
client; warm same-scope `hydrate` merges so soft navigation cannot discard
|
|
299
|
-
confirmed session data the next
|
|
377
|
+
confirmed session data the next boundary did not re-dehydrate. Layout
|
|
378
|
+
retention survives child navigation, page retention is replaced on page exit,
|
|
379
|
+
and exact layout/page duplicates share one replica watch until the final owner
|
|
380
|
+
releases it.
|
|
300
381
|
|
|
301
382
|
The replica stores normalized records and exact argument-sensitive indexes,
|
|
302
383
|
not GraphQL response blobs. Generated selection metadata reconstructs each
|
|
@@ -423,7 +504,7 @@ duplicated as decision documents in this package.
|
|
|
423
504
|
command runtime, query-plan helpers, and optional persistence.
|
|
424
505
|
- `@hops-ops/distributed/diagnostics` — redacted support snapshots and artifact
|
|
425
506
|
inspection.
|
|
426
|
-
- `@hops-ops/distributed/sveltekit` — Svelte stores, SSR
|
|
507
|
+
- `@hops-ops/distributed/sveltekit` — Svelte stores, island SSR composition,
|
|
427
508
|
hydration, auth lifecycle, and tree-local generated bindings.
|
|
428
509
|
- `@hops-ops/distributed/sveltekit/vite` — Node-only one-shot/check/watch
|
|
429
510
|
generation, virtual module aliases, and GraphQL HTTP/WebSocket proxy helpers.
|
|
@@ -34,6 +34,7 @@ export type ProtocolHost = {
|
|
|
34
34
|
setProtocolGeneration(value: ProtocolGeneration | undefined): void;
|
|
35
35
|
getProtocolGenerationSequence(): number;
|
|
36
36
|
bumpProtocolGenerationSequence(): void;
|
|
37
|
+
disposeAuthorizationGeneration(): void;
|
|
37
38
|
getTrustedPresets(): readonly DistributedTrustedPreset[];
|
|
38
39
|
setTrustedPresets(value: readonly DistributedTrustedPreset[]): void;
|
|
39
40
|
getCommandAuthorityContract(): RegisteredCommandAuthorityContract | undefined;
|
|
@@ -107,6 +107,7 @@ export function purgeProtocolGeneration(host) {
|
|
|
107
107
|
}
|
|
108
108
|
export function closeAuthorizationGeneration(host) {
|
|
109
109
|
host.bumpProtocolGenerationSequence();
|
|
110
|
+
host.disposeAuthorizationGeneration();
|
|
110
111
|
host.abortAuthorization();
|
|
111
112
|
host.closeActiveTransports();
|
|
112
113
|
}
|
|
@@ -22,6 +22,7 @@ export class DistributedReplicaImpl {
|
|
|
22
22
|
#engine;
|
|
23
23
|
#transport;
|
|
24
24
|
#reportObserverError;
|
|
25
|
+
#onAuthorizationGenerationDispose;
|
|
25
26
|
#diagnostics;
|
|
26
27
|
#diagnosticLayers;
|
|
27
28
|
#inFlight = new Map();
|
|
@@ -68,6 +69,8 @@ export class DistributedReplicaImpl {
|
|
|
68
69
|
constructor(options = {}) {
|
|
69
70
|
this.#transport = options.transport;
|
|
70
71
|
this.#reportObserverError = options.onObserverError ?? reportUnhandledObserverError;
|
|
72
|
+
this.#onAuthorizationGenerationDispose =
|
|
73
|
+
options.onAuthorizationGenerationDispose;
|
|
71
74
|
this.#diagnostics = options.diagnostics;
|
|
72
75
|
this.#diagnosticLayers =
|
|
73
76
|
options.diagnostics === undefined ? undefined : new Map();
|
|
@@ -209,6 +212,14 @@ export class DistributedReplicaImpl {
|
|
|
209
212
|
bumpProtocolGenerationSequence: () => {
|
|
210
213
|
self.#protocolGenerationSequence += 1;
|
|
211
214
|
},
|
|
215
|
+
disposeAuthorizationGeneration: () => {
|
|
216
|
+
try {
|
|
217
|
+
self.#onAuthorizationGenerationDispose?.();
|
|
218
|
+
}
|
|
219
|
+
catch (error) {
|
|
220
|
+
self._reportObserverErrors([error]);
|
|
221
|
+
}
|
|
222
|
+
},
|
|
212
223
|
getTrustedPresets: () => self.#trustedPresets,
|
|
213
224
|
setTrustedPresets: (value) => {
|
|
214
225
|
self.#trustedPresets = value;
|
|
@@ -11,6 +11,7 @@ export class ReplicaWatchState {
|
|
|
11
11
|
#snapshot;
|
|
12
12
|
#identitySignature;
|
|
13
13
|
#destroyed = false;
|
|
14
|
+
#autoFetchScheduled = false;
|
|
14
15
|
#unregister;
|
|
15
16
|
constructor(owner, artifact, variables, options) {
|
|
16
17
|
this.#owner = owner;
|
|
@@ -57,7 +58,8 @@ export class ReplicaWatchState {
|
|
|
57
58
|
if (this.#destroyed)
|
|
58
59
|
return;
|
|
59
60
|
this.materialized = materialized;
|
|
60
|
-
this.#sync(
|
|
61
|
+
this.#sync(false);
|
|
62
|
+
this.#scheduleAutoFetch();
|
|
61
63
|
}
|
|
62
64
|
_stateChanged(allowFetch) {
|
|
63
65
|
if (this.#destroyed)
|
|
@@ -92,4 +94,14 @@ export class ReplicaWatchState {
|
|
|
92
94
|
if (allowFetch)
|
|
93
95
|
void this.#owner._fetch(this, false);
|
|
94
96
|
}
|
|
97
|
+
#scheduleAutoFetch() {
|
|
98
|
+
if (this.#autoFetchScheduled || this.#destroyed)
|
|
99
|
+
return;
|
|
100
|
+
this.#autoFetchScheduled = true;
|
|
101
|
+
queueMicrotask(() => {
|
|
102
|
+
this.#autoFetchScheduled = false;
|
|
103
|
+
if (!this.#destroyed)
|
|
104
|
+
void this.#owner._fetch(this, false);
|
|
105
|
+
});
|
|
106
|
+
}
|
|
95
107
|
}
|
|
@@ -3,6 +3,7 @@ import type { ReplicaOperationArtifact, ReplicaVariableCodecArtifact, ReplicaVar
|
|
|
3
3
|
export type VariableCodecRegistry = {
|
|
4
4
|
readonly limits: ReplicaVariableCodecLimits;
|
|
5
5
|
readonly variables: ReadonlyMap<string, ReplicaVariableInputRef>;
|
|
6
|
+
readonly defaults: ReadonlyMap<string, ReplicaValue>;
|
|
6
7
|
readonly inputs: ReadonlyMap<string, ReplicaVariableInputDefinition>;
|
|
7
8
|
};
|
|
8
9
|
/**
|
|
@@ -24,6 +24,10 @@ export function canonicalizeOperationVariables(artifact, variables) {
|
|
|
24
24
|
for (const [name, input] of [...registry.variables].sort(([left], [right]) => compareCodeUnits(left, right))) {
|
|
25
25
|
const present = supplied.has(name) && supplied.get(name) !== undefined;
|
|
26
26
|
if (!present) {
|
|
27
|
+
if (registry.defaults.has(name)) {
|
|
28
|
+
canonical.push([name, registry.defaults.get(name)]);
|
|
29
|
+
continue;
|
|
30
|
+
}
|
|
27
31
|
if (!input.nullable) {
|
|
28
32
|
variableValueInvalid(`variables.${name}`, 'required variable is missing');
|
|
29
33
|
}
|
|
@@ -37,8 +41,8 @@ export function canonicalizeOperationVariables(artifact, variables) {
|
|
|
37
41
|
return freezeRecord(canonical);
|
|
38
42
|
}
|
|
39
43
|
export function validateVariableCodec(codec) {
|
|
40
|
-
const root = artifactRecord(codec, 'artifact.variableCodec', ['version', 'limits', 'variables', 'inputs']);
|
|
41
|
-
if (root.version !==
|
|
44
|
+
const root = artifactRecord(codec, 'artifact.variableCodec', ['version', 'limits', 'variables', 'defaults', 'inputs']);
|
|
45
|
+
if (root.version !== 2)
|
|
42
46
|
variableCodecInvalid('artifact.variableCodec.version');
|
|
43
47
|
const rawLimits = artifactRecord(root.limits, 'artifact.variableCodec.limits', ['maxDepth', 'maxBoolWidth', 'maxInList']);
|
|
44
48
|
const limits = {
|
|
@@ -62,7 +66,16 @@ export function validateVariableCodec(codec) {
|
|
|
62
66
|
for (const [name, definition] of inputs) {
|
|
63
67
|
validateInputDefinition(definition, `artifact.variableCodec.inputs.${name}`, inputs, new Set(), 0);
|
|
64
68
|
}
|
|
65
|
-
|
|
69
|
+
const defaults = new Map();
|
|
70
|
+
const registry = { limits, variables, defaults, inputs };
|
|
71
|
+
for (const [name, value] of artifactRecordEntries(root.defaults, 'artifact.variableCodec.defaults')) {
|
|
72
|
+
const input = variables.get(name);
|
|
73
|
+
if (input === undefined) {
|
|
74
|
+
variableCodecInvalid(`artifact.variableCodec.defaults.${name}`);
|
|
75
|
+
}
|
|
76
|
+
defaults.set(name, canonicalizeInputRef(input, value, registry, `artifact.variableCodec.defaults.${name}`, new Set(), 0));
|
|
77
|
+
}
|
|
78
|
+
return registry;
|
|
66
79
|
}
|
|
67
80
|
export function validateInputRef(value, path, inputs, limits, active, depth) {
|
|
68
81
|
checkCodecDepth(depth, path);
|
package/dist/replica/index.d.ts
CHANGED
|
@@ -17,6 +17,6 @@ export { compareReplicaOrder, decideReplicaPaginationMaintenance, evaluateReplic
|
|
|
17
17
|
export { createReplicaIndexMaintenanceRegistry, formatReplicaIndexStaleReason } from './index-maintenance.js';
|
|
18
18
|
export type { ReplicaIndexDependencyChange, ReplicaIndexMaintenanceDecision, ReplicaIndexMaintenanceIndex, ReplicaIndexMaintenanceReason, ReplicaIndexMaintenanceReasonCode, ReplicaIndexMaintenanceRecord, ReplicaIndexMaintenanceRegistry, ReplicaIndexMaintenanceSnapshot, ReplicaIndexPlanRegistration, ReplicaIndexRecordChange, ReplicaIndexRelationshipChange, ReplicaIndexSemanticChange, ReplicaIndexSemanticLayer } from './index-maintenance.js';
|
|
19
19
|
export type { ReplicaFilterEvaluation, ReplicaFilterEvaluationOptions, ReplicaOrderComparison, ReplicaPaginationChange, ReplicaPaginationMaintenanceDecision, ReplicaQueryPlanPath, ReplicaQueryPlanReason, ReplicaQueryPlanReasonCode, ReplicaRelationshipFilterRequest } from './query-plan.js';
|
|
20
|
-
export type { DistributedReplicaOptions, DistributedReplica, ReplicaArgumentsArtifact, ReplicaArgumentValue, ReplicaAuthoritativeScope, ReplicaBaseWriter, ReplicaBranchSemantic, ReplicaClientSurface, ReplicaCoverageArtifact, ReplicaDehydratedState, ReplicaFilterArtifact, ReplicaFilterExpression, ReplicaFilterFieldArtifact, ReplicaFilterLiteral, ReplicaFilterOperand, ReplicaFilterOperator, ReplicaIdentity, ReplicaIndexCoverage, ReplicaIndexInspection, ReplicaIndexTarget, ReplicaListValue, ReplicaLiveObserver, ReplicaLiveState, ReplicaLiteralValue, ReplicaModelArtifact, ReplicaObjectBranch, ReplicaObjectMember, ReplicaObjectSelection, ReplicaObjectValue, ReplicaOperationArtifact, ReplicaOperationSourceLocation, ReplicaOperationProtocol, ReplicaOrderArtifact, ReplicaOrderFieldArtifact, ReplicaOrderTieBreakerArtifact, ReplicaOptimisticWriter, ReplicaPaginationArtifact, ReplicaPaginationDisposition, ReplicaProtocolOperationArtifact, ReplicaRecordInspection, ReplicaRecordPatch, ReplicaRevalidationPlan, ReplicaRevalidationRelationship, ReplicaRevision, ReplicaRelationshipArtifact, ReplicaRelationshipKeyMapping, ReplicaRelationshipKind, ReplicaResultEnvelope, ReplicaRowPolicyArtifact, ReplicaRootSelection, ReplicaScalarSelection, ReplicaSelectionStorage, ReplicaSparse, ReplicaSnapshot, ReplicaStatus, ReplicaTransport, ReplicaTransportRequest, ReplicaVariableValue, ReplicaVariableCodecArtifact, ReplicaVariableEnumInputRef, ReplicaVariableFilterInputDefinition, ReplicaVariableFilterInputField, ReplicaVariableFilterInputRelationship, ReplicaVariableFilterInputTarget, ReplicaVariableInputDefinition, ReplicaVariableInputRef, ReplicaVariableListInputRef, ReplicaVariableNamedInputRef, ReplicaVariableOrderInputDefinition, ReplicaVariableOrderInputField, ReplicaVariableScalarInputRef, ReplicaValue, ReplicaWatch, ReplicaWriteSource, WatchReplicaOptions } from './types.js';
|
|
20
|
+
export type { DistributedReplicaOptions, DistributedReplica, ReplicaArgumentsArtifact, ReplicaArgumentValue, ReplicaAuthoritativeScope, ReplicaBaseWriter, ReplicaBranchSemantic, ReplicaClientSurface, ReplicaCoverageArtifact, ReplicaDehydratedState, ReplicaFilterArtifact, ReplicaFilterExpression, ReplicaFilterFieldArtifact, ReplicaFilterLiteral, ReplicaFilterOperand, ReplicaFilterOperator, ReplicaIdentity, ReplicaIndexCoverage, ReplicaIndexInspection, ReplicaIndexTarget, ReplicaIslandMetadata, ReplicaIslandOperation, ReplicaListValue, ReplicaLiveObserver, ReplicaLiveState, ReplicaLiteralValue, ReplicaModelArtifact, ReplicaObjectBranch, ReplicaObjectMember, ReplicaObjectSelection, ReplicaObjectValue, ReplicaOperationArtifact, ReplicaOperationSourceLocation, ReplicaOperationProtocol, ReplicaOrderArtifact, ReplicaOrderFieldArtifact, ReplicaOrderTieBreakerArtifact, ReplicaOptimisticWriter, ReplicaPaginationArtifact, ReplicaPaginationDisposition, ReplicaProtocolOperationArtifact, ReplicaRecordInspection, ReplicaRecordPatch, ReplicaRevalidationPlan, ReplicaRevalidationRelationship, ReplicaRevision, ReplicaRelationshipArtifact, ReplicaRelationshipKeyMapping, ReplicaRelationshipKind, ReplicaResultEnvelope, ReplicaRowPolicyArtifact, ReplicaRootSelection, ReplicaScalarSelection, ReplicaSelectionStorage, ReplicaSparse, ReplicaSnapshot, ReplicaStatus, ReplicaTransport, ReplicaTransportRequest, ReplicaVariableValue, ReplicaVariableCodecArtifact, ReplicaVariableEnumInputRef, ReplicaVariableFilterInputDefinition, ReplicaVariableFilterInputField, ReplicaVariableFilterInputRelationship, ReplicaVariableFilterInputTarget, ReplicaVariableInputDefinition, ReplicaVariableInputRef, ReplicaVariableListInputRef, ReplicaVariableNamedInputRef, ReplicaVariableOrderInputDefinition, ReplicaVariableOrderInputField, ReplicaVariableScalarInputRef, ReplicaValue, ReplicaWatch, ReplicaWriteSource, WatchReplicaOptions } from './types.js';
|
|
21
21
|
export { lowerMutationCache, MUTATION_CACHE_VISIBILITY_FULL, MUTATION_CACHE_VISIBILITY_UNAUTHORIZED, } from './mutation-cache.js';
|
|
22
22
|
export type { MutationCacheEffect, MutationCacheProgram, MutationCacheVisibility, MutationField, MutationOperation, MutationProgram, MutationTarget, } from './mutation-cache.js';
|
package/dist/replica/types.d.ts
CHANGED
|
@@ -150,9 +150,11 @@ export type ReplicaVariableCodecLimits = {
|
|
|
150
150
|
};
|
|
151
151
|
/** Exact variable codec emitted beside a generated operation artifact. */
|
|
152
152
|
export type ReplicaVariableCodecArtifact = {
|
|
153
|
-
readonly version:
|
|
153
|
+
readonly version: 2;
|
|
154
154
|
readonly limits: ReplicaVariableCodecLimits;
|
|
155
155
|
readonly variables: Readonly<Record<string, ReplicaVariableInputRef>>;
|
|
156
|
+
/** Canonical GraphQL defaults, applied before cache identity or transport. */
|
|
157
|
+
readonly defaults: Readonly<Record<string, ReplicaValue>>;
|
|
156
158
|
readonly inputs: Readonly<Record<string, ReplicaVariableInputDefinition>>;
|
|
157
159
|
};
|
|
158
160
|
export type ReplicaFilterOperator = '_eq' | '_neq' | '_gt' | '_gte' | '_lt' | '_lte' | '_in' | '_nin' | '_is_null' | '_like' | '_ilike' | '_contains' | '_contained_in' | '_has_key';
|
|
@@ -444,6 +446,40 @@ export type ReplicaProtocolOperationArtifact<TData = Record<string, unknown>, TV
|
|
|
444
446
|
readonly variableCodec: ReplicaVariableCodecArtifact;
|
|
445
447
|
};
|
|
446
448
|
export type ReplicaOperationArtifact<TData = Record<string, unknown>, TVariables extends GraphqlVariables = GraphqlVariables> = ReplicaProtocolOperationArtifact<TData, TVariables>;
|
|
449
|
+
/** Framework-neutral compiler metadata consumed by placement adapters. */
|
|
450
|
+
export type ReplicaIslandMetadata = {
|
|
451
|
+
readonly version: 1;
|
|
452
|
+
readonly id: string;
|
|
453
|
+
readonly operation: string;
|
|
454
|
+
readonly operationHash: string;
|
|
455
|
+
readonly modulePath: string;
|
|
456
|
+
readonly exportName: string;
|
|
457
|
+
readonly source: ReplicaOperationSourceLocation;
|
|
458
|
+
readonly directives: {
|
|
459
|
+
readonly load: boolean;
|
|
460
|
+
readonly live: boolean;
|
|
461
|
+
};
|
|
462
|
+
readonly variableSchema: {
|
|
463
|
+
readonly reference: string;
|
|
464
|
+
readonly codecVersion: number;
|
|
465
|
+
readonly variables: readonly {
|
|
466
|
+
readonly name: string;
|
|
467
|
+
readonly graphqlType: string;
|
|
468
|
+
readonly defaultValue?: ReplicaValue;
|
|
469
|
+
}[];
|
|
470
|
+
};
|
|
471
|
+
readonly liveCoverage: {
|
|
472
|
+
readonly requested: boolean;
|
|
473
|
+
readonly finite: boolean;
|
|
474
|
+
readonly kind: string;
|
|
475
|
+
readonly maxItems?: number;
|
|
476
|
+
};
|
|
477
|
+
};
|
|
478
|
+
/** One adapter-consumable island plan bound to its executable operation. */
|
|
479
|
+
export type ReplicaIslandOperation<TData = Record<string, unknown>, TVariables extends GraphqlVariables = GraphqlVariables> = {
|
|
480
|
+
readonly plan: ReplicaIslandMetadata;
|
|
481
|
+
readonly artifact: ReplicaOperationArtifact<TData, TVariables>;
|
|
482
|
+
};
|
|
447
483
|
export type ReplicaWriteSource = 'network' | 'live' | 'ssr' | 'restore' | 'atomic';
|
|
448
484
|
export type ReplicaResultEnvelope<TData = unknown> = {
|
|
449
485
|
readonly data?: TData | null;
|
|
@@ -532,6 +568,11 @@ export type WatchReplicaOptions = {
|
|
|
532
568
|
export type DistributedReplicaOptions = {
|
|
533
569
|
readonly transport?: ReplicaTransport;
|
|
534
570
|
readonly onObserverError?: (error: AggregateError) => void;
|
|
571
|
+
/**
|
|
572
|
+
* Runs after the old generation is fenced and before its transports/state
|
|
573
|
+
* are purged. Framework adapters use this to release generation-owned views.
|
|
574
|
+
*/
|
|
575
|
+
readonly onAuthorizationGenerationDispose?: () => void;
|
|
535
576
|
/** Opt-in framework-neutral diagnostics; absent in production by default. */
|
|
536
577
|
readonly diagnostics?: ReplicaDiagnosticsSink;
|
|
537
578
|
};
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import type { DistributedReplica } from '../replica/index.js';
|
|
2
|
+
import type { DistributedBoundaryOperation, DistributedBoundaryVariableContext } from './boundary-variables.js';
|
|
3
|
+
export type DistributedSvelteKitBoundaryInstance = Readonly<{
|
|
4
|
+
/** Opaque identity for one mounted SvelteKit page or layout instance. */
|
|
5
|
+
id: string;
|
|
6
|
+
route: string;
|
|
7
|
+
kind: 'layout' | 'page';
|
|
8
|
+
}>;
|
|
9
|
+
export type DistributedSvelteKitBoundaryLocation = Readonly<{
|
|
10
|
+
/** Opaque identity for one mounted page or layout instance. */
|
|
11
|
+
id: string;
|
|
12
|
+
pathname: string;
|
|
13
|
+
kind: 'layout' | 'page';
|
|
14
|
+
}>;
|
|
15
|
+
export type DistributedSvelteKitLocationContext<TSession = unknown, TProps = Readonly<Record<string, unknown>>> = Omit<DistributedBoundaryVariableContext<TSession, TProps>, 'params'>;
|
|
16
|
+
export type SveltekitBoundaryLifecycleDiagnostic = Readonly<{
|
|
17
|
+
action: 'acquire' | 'retain' | 'release' | 'scope-dispose' | 'final-unsubscribe';
|
|
18
|
+
boundary: string;
|
|
19
|
+
operation?: string;
|
|
20
|
+
live?: boolean;
|
|
21
|
+
owners: number;
|
|
22
|
+
}>;
|
|
23
|
+
export type SveltekitBoundaryRetention = Readonly<{
|
|
24
|
+
release(): void;
|
|
25
|
+
}>;
|
|
26
|
+
export declare class DistributedSvelteKitBoundaryController {
|
|
27
|
+
#private;
|
|
28
|
+
constructor(replica: DistributedReplica, operations: readonly DistributedBoundaryOperation[], diagnostic?: (event: SveltekitBoundaryLifecycleDiagnostic) => void);
|
|
29
|
+
retain<TSession, TProps>(instance: DistributedSvelteKitBoundaryInstance, context: DistributedBoundaryVariableContext<TSession, TProps>): SveltekitBoundaryRetention;
|
|
30
|
+
/** Retain the nearest generated page/layout boundary at a browser location. */
|
|
31
|
+
retainLocation<TSession, TProps>(location: DistributedSvelteKitBoundaryLocation, context: DistributedSvelteKitLocationContext<TSession, TProps>): SveltekitBoundaryRetention;
|
|
32
|
+
/** Warm every generated page and owning layout selection for one target URL. */
|
|
33
|
+
prefetchLocation<TSession, TProps>(pathname: string, context: DistributedSvelteKitLocationContext<TSession, TProps>): Promise<void>;
|
|
34
|
+
/** Close every old-scope owner while keeping the controller reusable. */
|
|
35
|
+
disposeScope(): void;
|
|
36
|
+
destroy(): void;
|
|
37
|
+
}
|