nervur 0.10.0 → 0.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/being.mjs +5 -2
- package/blueprint.mjs +33 -20
- package/client.mjs +1 -1
- package/index.mjs +1 -1
- package/package.json +1 -1
- package/program.mjs +33 -0
package/being.mjs
CHANGED
|
@@ -143,7 +143,10 @@ const rotates = ({ mine }, from, nextPkHash) => {
|
|
|
143
143
|
.list('refs/')
|
|
144
144
|
.map((key) => ({ key, referred: mine.read(key) }))
|
|
145
145
|
.find(({ referred }) => referred?.nextPkHash === claim);
|
|
146
|
-
if (
|
|
146
|
+
if (
|
|
147
|
+
held === undefined ||
|
|
148
|
+
(held.key !== `refs/${from}` && mine.read(`refs/${from}`) !== undefined)
|
|
149
|
+
) {
|
|
147
150
|
return undefined;
|
|
148
151
|
}
|
|
149
152
|
mine.write(`refs/${from}`, { nextPkHash, rights: held.referred.rights });
|
|
@@ -261,7 +264,7 @@ const Being = ({ voice, address, deliver, modules, registry, vouched, watch }) =
|
|
|
261
264
|
});
|
|
262
265
|
return answer({ referred: from, rights: pending.rights });
|
|
263
266
|
}
|
|
264
|
-
if (op?.ask === undefined || program === undefined) {
|
|
267
|
+
if (op?.ask === undefined || program === undefined || !program.visible(rights)) {
|
|
265
268
|
return undefined;
|
|
266
269
|
}
|
|
267
270
|
const asked = await program.ask({
|
package/blueprint.mjs
CHANGED
|
@@ -167,12 +167,12 @@ const merged = (base, added) =>
|
|
|
167
167
|
]),
|
|
168
168
|
);
|
|
169
169
|
|
|
170
|
+
// Bare names, not Type.field pairs: X's "if create answers, it created"
|
|
171
|
+
// makes Query.create and Mutation.create one reserved word.
|
|
170
172
|
const doorsIn = (sdl) =>
|
|
171
173
|
parse(sdl)
|
|
172
|
-
.definitions.filter(
|
|
173
|
-
|
|
174
|
-
)
|
|
175
|
-
.flatMap((one) => (one.fields ?? []).map((field) => `${one.name.value}.${field.name.value}`));
|
|
174
|
+
.definitions.filter((one) => doorHolder(one) && ['Mutation', 'Query'].includes(one.name.value))
|
|
175
|
+
.flatMap((one) => (one.fields ?? []).map((field) => field.name.value));
|
|
176
176
|
|
|
177
177
|
const composed = (baseSource, addedSource) => {
|
|
178
178
|
try {
|
|
@@ -319,23 +319,36 @@ const Blueprint = (source) => {
|
|
|
319
319
|
rights,
|
|
320
320
|
schema,
|
|
321
321
|
// The directive definition stays: pointer.mjs runs buildSchema on this output.
|
|
322
|
-
sdlFor: (held) =>
|
|
323
|
-
|
|
322
|
+
sdlFor: (held) => {
|
|
323
|
+
const kept = document.definitions
|
|
324
|
+
.map((one) =>
|
|
325
|
+
doorHolder(one)
|
|
326
|
+
? {
|
|
327
|
+
...one,
|
|
328
|
+
fields: (one.fields ?? []).filter((field) => {
|
|
329
|
+
const allowed = rightsOf(field);
|
|
330
|
+
return allowed === undefined || allowed.includes(held);
|
|
331
|
+
}),
|
|
332
|
+
}
|
|
333
|
+
: one,
|
|
334
|
+
)
|
|
335
|
+
.filter((one) => !doorHolder(one) || one.fields.length > 0);
|
|
336
|
+
const defined = new Set(
|
|
337
|
+
kept
|
|
338
|
+
.filter((one) => one.kind === Kind.OBJECT_TYPE_DEFINITION)
|
|
339
|
+
.map((one) => one.name.value),
|
|
340
|
+
);
|
|
341
|
+
// A filtered view where only a part's extension survives must still
|
|
342
|
+
// stand alone as a schema, or the right it serves opens nothing.
|
|
343
|
+
return print({
|
|
324
344
|
...document,
|
|
325
|
-
definitions:
|
|
326
|
-
.
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
return allowed === undefined || allowed.includes(held);
|
|
333
|
-
}),
|
|
334
|
-
}
|
|
335
|
-
: one,
|
|
336
|
-
)
|
|
337
|
-
.filter((one) => !doorHolder(one) || one.fields.length > 0),
|
|
338
|
-
}),
|
|
345
|
+
definitions: kept.map((one) =>
|
|
346
|
+
one.kind === Kind.OBJECT_TYPE_EXTENSION && !defined.has(one.name.value)
|
|
347
|
+
? { ...one, kind: Kind.OBJECT_TYPE_DEFINITION }
|
|
348
|
+
: one,
|
|
349
|
+
),
|
|
350
|
+
});
|
|
351
|
+
},
|
|
339
352
|
trespass: [],
|
|
340
353
|
});
|
|
341
354
|
} catch {
|
package/client.mjs
CHANGED
package/index.mjs
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
export { ADMIN } from './admin.mjs';
|
|
2
2
|
export { Blueprint, CLASSES, CORE_ONLY, OPEN, STRUCTURAL, coreClass, reads } from './blueprint.mjs';
|
|
3
|
-
export { Client } from './client.mjs';
|
|
3
|
+
export { Client, speaking } from './client.mjs';
|
|
4
4
|
export { Contract, Contracts } from './contract.mjs';
|
|
5
5
|
export { FLOOR, GROUND, Ground } from './ground.mjs';
|
|
6
6
|
export { Cells, Clock, Dns, Entropy, Keychain, Memory, Paths, Wire } from './modules.mjs';
|
package/package.json
CHANGED
package/program.mjs
CHANGED
|
@@ -4,6 +4,8 @@ import {
|
|
|
4
4
|
getIntrospectionQuery,
|
|
5
5
|
graphql,
|
|
6
6
|
isObjectType,
|
|
7
|
+
parse,
|
|
8
|
+
validate,
|
|
7
9
|
} from 'graphql';
|
|
8
10
|
import { Blueprint } from './blueprint.mjs';
|
|
9
11
|
|
|
@@ -41,8 +43,39 @@ const Program = (source) => {
|
|
|
41
43
|
}
|
|
42
44
|
return curtained.get(held);
|
|
43
45
|
};
|
|
46
|
+
// graphql's validator demands a Query root even to judge a mutation, so an
|
|
47
|
+
// all-mutation filtered world validates against a copy wearing an empty one
|
|
48
|
+
// — never printed, never executed against.
|
|
49
|
+
const askable = new Map();
|
|
50
|
+
const askableBy = (held) => {
|
|
51
|
+
if (!askable.has(held)) {
|
|
52
|
+
const seen = seenBy(held);
|
|
53
|
+
try {
|
|
54
|
+
askable.set(
|
|
55
|
+
held,
|
|
56
|
+
seen === undefined || seen.getQueryType() != null
|
|
57
|
+
? seen
|
|
58
|
+
: buildSchema(`${blueprint.sdlFor(held)}\ntype Query { _stands: Boolean }`),
|
|
59
|
+
);
|
|
60
|
+
} catch {
|
|
61
|
+
askable.set(held, undefined);
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
return askable.get(held);
|
|
65
|
+
};
|
|
44
66
|
return Object.freeze({
|
|
45
67
|
ask: async ({ source: asked, variables, context }) => {
|
|
68
|
+
const seen = askableBy(context.rights);
|
|
69
|
+
if (seen === undefined) {
|
|
70
|
+
return undefined;
|
|
71
|
+
}
|
|
72
|
+
try {
|
|
73
|
+
if (validate(seen, parse(asked)).length > 0) {
|
|
74
|
+
return undefined;
|
|
75
|
+
}
|
|
76
|
+
} catch {
|
|
77
|
+
return undefined;
|
|
78
|
+
}
|
|
46
79
|
const answered = await graphql({
|
|
47
80
|
contextValue: context,
|
|
48
81
|
schema,
|