@lovrozagar/oat 0.12.3 → 0.12.5
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/dist/config/define-config.d.ts +8 -1
- package/dist/config/define-config.d.ts.map +1 -1
- package/dist/config/define-config.js.map +1 -1
- package/dist/conformance/suite.d.ts.map +1 -1
- package/dist/conformance/suite.js +3 -1
- package/dist/conformance/suite.js.map +1 -1
- package/dist/reference/defects.d.ts +7 -0
- package/dist/reference/defects.d.ts.map +1 -1
- package/dist/reference/defects.js +7 -0
- package/dist/reference/defects.js.map +1 -1
- package/dist/reference/http.d.ts.map +1 -1
- package/dist/reference/http.js +17 -0
- package/dist/reference/http.js.map +1 -1
- package/dist/reference/spec.d.ts.map +1 -1
- package/dist/reference/spec.js +39 -0
- package/dist/reference/spec.js.map +1 -1
- package/dist/report/console.d.ts.map +1 -1
- package/dist/report/console.js +5 -0
- package/dist/report/console.js.map +1 -1
- package/dist/runtime/check-costs.d.ts.map +1 -1
- package/dist/runtime/check-costs.js +1 -0
- package/dist/runtime/check-costs.js.map +1 -1
- package/dist/runtime/check-ids.d.ts +1 -1
- package/dist/runtime/check-ids.d.ts.map +1 -1
- package/dist/runtime/check-ids.js +1 -0
- package/dist/runtime/check-ids.js.map +1 -1
- package/dist/runtime/checks.d.ts.map +1 -1
- package/dist/runtime/checks.js +2 -0
- package/dist/runtime/checks.js.map +1 -1
- package/dist/runtime/input.js +1 -0
- package/dist/runtime/input.js.map +1 -1
- package/dist/runtime/run.d.ts.map +1 -1
- package/dist/runtime/run.js +24 -1
- package/dist/runtime/run.js.map +1 -1
- package/dist/runtime/scope.d.ts.map +1 -1
- package/dist/runtime/scope.js +3 -0
- package/dist/runtime/scope.js.map +1 -1
- package/dist/runtime/self.d.ts +37 -0
- package/dist/runtime/self.d.ts.map +1 -0
- package/dist/runtime/self.js +192 -0
- package/dist/runtime/self.js.map +1 -0
- package/docs/configuration.md +1 -1
- package/docs/tags.md +2 -0
- package/package.json +1 -1
|
@@ -0,0 +1,192 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `x-entity.identity: self` — the signed-up caller is the record.
|
|
3
|
+
* There is no list and no create. A read returns that caller. An update is still there
|
|
4
|
+
* on the next read. No token is a 401.
|
|
5
|
+
*/
|
|
6
|
+
import { requestContentOf } from "./body.js";
|
|
7
|
+
import { ASSERTED } from "./finding.js";
|
|
8
|
+
import { fillPath } from "./world.js";
|
|
9
|
+
export const SELF_IDENTITY = "self";
|
|
10
|
+
export const SELF_CHECK_ID = "auth.self-is-the-caller";
|
|
11
|
+
const PREFERRED_FIELDS = ["first_name", "display_name", "name", "nickname"];
|
|
12
|
+
export function selfOperationIds(entity) {
|
|
13
|
+
if (entity.identity !== SELF_IDENTITY)
|
|
14
|
+
return [];
|
|
15
|
+
return [entity.read, entity.update].filter((id) => id !== undefined);
|
|
16
|
+
}
|
|
17
|
+
export function entityIsSelf(entity) {
|
|
18
|
+
return selfOperationIds(entity).length > 0;
|
|
19
|
+
}
|
|
20
|
+
function asSchema(value) {
|
|
21
|
+
if (value === null || typeof value !== "object" || Array.isArray(value))
|
|
22
|
+
return null;
|
|
23
|
+
return value;
|
|
24
|
+
}
|
|
25
|
+
/** A nullable union is the non-null branch. `type: ["string", "null"]` is a string. */
|
|
26
|
+
function unwrap(schema) {
|
|
27
|
+
const branches = Array.isArray(schema.anyOf) ? schema.anyOf : Array.isArray(schema.oneOf) ? schema.oneOf : null;
|
|
28
|
+
if (branches !== null) {
|
|
29
|
+
const nonNull = branches
|
|
30
|
+
.map(asSchema)
|
|
31
|
+
.filter((branch) => branch !== null && branch.type !== "null");
|
|
32
|
+
const only = nonNull.length === 1 ? nonNull[0] : undefined;
|
|
33
|
+
if (only !== undefined)
|
|
34
|
+
return unwrap(only);
|
|
35
|
+
}
|
|
36
|
+
if (Array.isArray(schema.type)) {
|
|
37
|
+
const types = schema.type.filter((type) => type !== "null");
|
|
38
|
+
if (types.length === 1)
|
|
39
|
+
return { ...schema, type: types[0] };
|
|
40
|
+
}
|
|
41
|
+
return schema;
|
|
42
|
+
}
|
|
43
|
+
function probeField(schema) {
|
|
44
|
+
const root = asSchema(schema);
|
|
45
|
+
if (root === null)
|
|
46
|
+
return null;
|
|
47
|
+
const properties = unwrap(root).properties;
|
|
48
|
+
if (properties === null || typeof properties !== "object")
|
|
49
|
+
return null;
|
|
50
|
+
const record = properties;
|
|
51
|
+
const names = [
|
|
52
|
+
...PREFERRED_FIELDS.filter((name) => record[name] !== undefined),
|
|
53
|
+
...Object.keys(record).filter((name) => !PREFERRED_FIELDS.includes(name)),
|
|
54
|
+
];
|
|
55
|
+
for (const name of names) {
|
|
56
|
+
const raw = asSchema(record[name]);
|
|
57
|
+
if (raw === null)
|
|
58
|
+
continue;
|
|
59
|
+
const rec = unwrap(raw);
|
|
60
|
+
if (rec.type !== "string")
|
|
61
|
+
continue;
|
|
62
|
+
if (rec.readOnly === true)
|
|
63
|
+
continue;
|
|
64
|
+
if (rec.format === "email" || rec.format === "uri" || rec.format === "date-time")
|
|
65
|
+
continue;
|
|
66
|
+
if (typeof rec.pattern === "string")
|
|
67
|
+
continue;
|
|
68
|
+
const maxLength = typeof rec.maxLength === "number" ? rec.maxLength : 64;
|
|
69
|
+
if (maxLength < 4)
|
|
70
|
+
continue;
|
|
71
|
+
return { maxLength, name };
|
|
72
|
+
}
|
|
73
|
+
return null;
|
|
74
|
+
}
|
|
75
|
+
function nextValue(maxLength, current) {
|
|
76
|
+
const primary = "Oat".slice(0, maxLength);
|
|
77
|
+
const alternate = "Xot".slice(0, maxLength);
|
|
78
|
+
return current === primary ? alternate : primary;
|
|
79
|
+
}
|
|
80
|
+
function operation(model, id) {
|
|
81
|
+
return id === undefined ? undefined : model.byOperationId.get(id);
|
|
82
|
+
}
|
|
83
|
+
function pathOf(op) {
|
|
84
|
+
try {
|
|
85
|
+
return fillPath(op.path, {});
|
|
86
|
+
}
|
|
87
|
+
catch {
|
|
88
|
+
return null;
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
export async function runSelfIdentity(input) {
|
|
92
|
+
const readOp = operation(input.model, input.entity.read);
|
|
93
|
+
const updateOp = operation(input.model, input.entity.update);
|
|
94
|
+
const ops = selfOperationIds(input.entity);
|
|
95
|
+
const findings = input.findings.attributed(ops).ownedBy(SELF_CHECK_ID);
|
|
96
|
+
const probe = readOp ?? updateOp;
|
|
97
|
+
if (probe === undefined)
|
|
98
|
+
return findings.unresolved(SELF_CHECK_ID, input.entity.name, "no read or update");
|
|
99
|
+
const probePath = pathOf(probe);
|
|
100
|
+
if (probePath === null) {
|
|
101
|
+
return findings.unresolved(SELF_CHECK_ID, input.entity.name, `${probe.operationId} needs a path id`);
|
|
102
|
+
}
|
|
103
|
+
const anonymous = await input.client.request(probe.method, probePath, {
|
|
104
|
+
headers: {},
|
|
105
|
+
operationId: probe.operationId,
|
|
106
|
+
skipAuthRefresh: true,
|
|
107
|
+
});
|
|
108
|
+
if (anonymous.status !== 401) {
|
|
109
|
+
return findings.security(SELF_CHECK_ID, input.entity.name, "the caller route answered without a token", `${probe.operationId} returned ${anonymous.status} with no credential. The signed-up caller is the record, so no token is a 401.`, [anonymous]);
|
|
110
|
+
}
|
|
111
|
+
if (readOp === undefined) {
|
|
112
|
+
const updatePath = pathOf(updateOp);
|
|
113
|
+
if (updatePath === null || updateOp === undefined)
|
|
114
|
+
return ASSERTED;
|
|
115
|
+
const wrote = await sendUpdate(input.client, updateOp, updatePath, input.auth, { note: "Oat" });
|
|
116
|
+
if (wrote.status < 200 || wrote.status >= 300) {
|
|
117
|
+
return findings.backend(SELF_CHECK_ID, input.entity.name, "updating the caller failed", `${updateOp.operationId} returned ${wrote.status} for the signed-up caller.`, [anonymous, wrote]);
|
|
118
|
+
}
|
|
119
|
+
return ASSERTED;
|
|
120
|
+
}
|
|
121
|
+
const readPath = pathOf(readOp);
|
|
122
|
+
if (readPath === null)
|
|
123
|
+
return findings.unresolved(SELF_CHECK_ID, input.entity.name, "the read needs a path id");
|
|
124
|
+
const read = await input.client.request(readOp.method, readPath, {
|
|
125
|
+
headers: input.auth,
|
|
126
|
+
operationId: readOp.operationId,
|
|
127
|
+
});
|
|
128
|
+
if (read.status !== 200) {
|
|
129
|
+
return findings.backend(SELF_CHECK_ID, input.entity.name, "reading the caller failed", `${readOp.operationId} returned ${read.status} for the signed-up caller. The read is that caller and returns 200.`, [anonymous, read]);
|
|
130
|
+
}
|
|
131
|
+
if (updateOp === undefined)
|
|
132
|
+
return ASSERTED;
|
|
133
|
+
const updatePath = pathOf(updateOp);
|
|
134
|
+
if (updatePath === null)
|
|
135
|
+
return ASSERTED;
|
|
136
|
+
const content = requestContentOf(updateOp, input.model);
|
|
137
|
+
const field = probeField(content?.schema);
|
|
138
|
+
if (field === null) {
|
|
139
|
+
return findings.unresolved(SELF_CHECK_ID, input.entity.name, "the update has no plain string field to change");
|
|
140
|
+
}
|
|
141
|
+
const before = read.responseBody;
|
|
142
|
+
const current = before !== null && typeof before === "object" ? before[field.name] : undefined;
|
|
143
|
+
const value = nextValue(field.maxLength, current);
|
|
144
|
+
const wrote = await sendUpdate(input.client, updateOp, updatePath, input.auth, { [field.name]: value });
|
|
145
|
+
if (wrote.status < 200 || wrote.status >= 300) {
|
|
146
|
+
return findings.backend(SELF_CHECK_ID, input.entity.name, "updating the caller failed", `${updateOp.operationId} returned ${wrote.status} when setting ${field.name}.`, [read, wrote]);
|
|
147
|
+
}
|
|
148
|
+
const again = await input.client.request(readOp.method, readPath, {
|
|
149
|
+
headers: input.auth,
|
|
150
|
+
operationId: readOp.operationId,
|
|
151
|
+
});
|
|
152
|
+
const seen = again.responseBody !== null && typeof again.responseBody === "object"
|
|
153
|
+
? again.responseBody[field.name]
|
|
154
|
+
: undefined;
|
|
155
|
+
if (again.status !== 200 || seen !== value) {
|
|
156
|
+
return findings.backend(SELF_CHECK_ID, input.entity.name, "an update to the caller did not stick", `${updateOp.operationId} set ${field.name} to ${JSON.stringify(value)}, and the next ${readOp.operationId} returned ${again.status} with ${JSON.stringify(seen)}.`, [wrote, again]);
|
|
157
|
+
}
|
|
158
|
+
if (typeof current === "string" || current === null) {
|
|
159
|
+
await sendUpdate(input.client, updateOp, updatePath, input.auth, { [field.name]: current });
|
|
160
|
+
}
|
|
161
|
+
return ASSERTED;
|
|
162
|
+
}
|
|
163
|
+
async function sendUpdate(client, op, path, auth, body) {
|
|
164
|
+
return client.request(op.method, path, {
|
|
165
|
+
body,
|
|
166
|
+
headers: auth,
|
|
167
|
+
operationId: op.operationId,
|
|
168
|
+
});
|
|
169
|
+
}
|
|
170
|
+
export const selfIdentityCheck = {
|
|
171
|
+
id: SELF_CHECK_ID,
|
|
172
|
+
mutates: true,
|
|
173
|
+
needs: "x-entity.identity: self, and a read or an update",
|
|
174
|
+
plan(ctx) {
|
|
175
|
+
const entity = ctx.model.entities.get(ctx.entityName);
|
|
176
|
+
if (entity === undefined || !entityIsSelf(entity)) {
|
|
177
|
+
return { ok: false, needs: "x-entity.identity: self, and a read or an update" };
|
|
178
|
+
}
|
|
179
|
+
return { ok: true, value: undefined };
|
|
180
|
+
},
|
|
181
|
+
async run(ctx) {
|
|
182
|
+
return runSelfIdentity({
|
|
183
|
+
auth: ctx.auth,
|
|
184
|
+
client: ctx.client,
|
|
185
|
+
entity: ctx.model.entities.get(ctx.entityName),
|
|
186
|
+
findings: ctx.findings,
|
|
187
|
+
model: ctx.model,
|
|
188
|
+
});
|
|
189
|
+
},
|
|
190
|
+
subjects: (entity) => selfOperationIds(entity),
|
|
191
|
+
};
|
|
192
|
+
//# sourceMappingURL=self.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"self.js","sourceRoot":"","sources":["../../src/runtime/self.ts"],"names":[],"mappings":"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"}
|
package/docs/configuration.md
CHANGED
|
@@ -534,7 +534,7 @@ Without `teardownPrincipal`, provisioned accounts are reported as leftover rathe
|
|
|
534
534
|
|
|
535
535
|
`resolveHeaders` is called on every dispatch (including the 401 retry). Merge order: `globalHeaders` → hook → per-request headers → principal credential. Use `ctx.operationId` / `ctx.method` / `ctx.url` to attach a one-shot captcha only on captcha ops. oat does not speak Turnstile.
|
|
536
536
|
|
|
537
|
-
`resolveInput` is the JSON twin of `resolveUpload`. Return a value to replace that field (`payment_method_id` on `billing.subscribe`); `null` keeps the generator.
|
|
537
|
+
`resolveInput` is the JSON twin of `resolveUpload`. Return a value to replace that field (`payment_method_id` on `billing.subscribe`); `null` keeps the generator. `request.value` is the generated value, or `undefined` when the field was left out. Return `null` for an omitted field or a value outside the schema's length or range bounds so a constraint check is the body the server receives.
|
|
538
538
|
|
|
539
539
|
`resolveQueryCapabilities` runs once per entity after seed. `get(operationId)` (or `"GET /path"`) uses the seeded parent scope so a follow-up read can harvest dynamic columns. A provided `filterable` / `sortable` / `searchable` / `selectable` list **replaces** that axis; omitted axes stay. JSON configs have no hook.
|
|
540
540
|
|
package/docs/tags.md
CHANGED
|
@@ -61,6 +61,8 @@ x-entity:
|
|
|
61
61
|
|
|
62
62
|
Overrides path-segment inference. `identity` is required when the item schema has no `id` (or `uuid` / `slug` / `key` / `name`).
|
|
63
63
|
|
|
64
|
+
`identity: self` means the signed-up caller is the record. The entity needs a read or an update and does not need a list or a create. The read returns 200. An update is still there on the next read. No token returns 401.
|
|
65
|
+
|
|
64
66
|
**Fallback:** deepest plural segment + HTTP verb. See [How the model is derived](model.md#how-the-model-is-derived).
|
|
65
67
|
|
|
66
68
|
### `x-invite`
|