@jskit-ai/json-rest-api-core 0.1.104-oldline.0 → 0.1.104
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/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@jskit-ai/json-rest-api-core",
|
|
3
|
-
"version": "0.1.104
|
|
3
|
+
"version": "0.1.104",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"scripts": {
|
|
6
6
|
"test": "node --test"
|
|
@@ -9,8 +9,45 @@
|
|
|
9
9
|
"./server/jsonRestApiHost": "./src/server/jsonRestApiHost.js"
|
|
10
10
|
},
|
|
11
11
|
"dependencies": {
|
|
12
|
+
"@jskit-ai/database-runtime": "0.1.160",
|
|
13
|
+
"@jskit-ai/kernel": "0.1.160",
|
|
14
|
+
"@jskit-ai/resource-crud-core": "0.1.102",
|
|
12
15
|
"hooked-api": "1.x.x",
|
|
13
|
-
"json-rest-api": "^1.0.27"
|
|
14
|
-
|
|
16
|
+
"json-rest-api": "^1.0.27"
|
|
17
|
+
},
|
|
18
|
+
"description": "Shared internal json-rest-api host runtime with autofilter, query-projection, and row-policy support.",
|
|
19
|
+
"jskit": {
|
|
20
|
+
"kind": "runtime",
|
|
21
|
+
"capabilities": {
|
|
22
|
+
"provides": [
|
|
23
|
+
"runtime.json-rest-api"
|
|
24
|
+
],
|
|
25
|
+
"requires": [
|
|
26
|
+
"runtime.database"
|
|
27
|
+
]
|
|
28
|
+
},
|
|
29
|
+
"runtime": {
|
|
30
|
+
"server": {
|
|
31
|
+
"providers": [
|
|
32
|
+
{
|
|
33
|
+
"entrypoint": "src/server/JsonRestApiProvider.js",
|
|
34
|
+
"export": "JsonRestApiProvider"
|
|
35
|
+
}
|
|
36
|
+
]
|
|
37
|
+
},
|
|
38
|
+
"client": {
|
|
39
|
+
"providers": []
|
|
40
|
+
}
|
|
41
|
+
},
|
|
42
|
+
"metadata": {
|
|
43
|
+
"apiSummary": {
|
|
44
|
+
"surfaces": [
|
|
45
|
+
{
|
|
46
|
+
"subpath": "./server",
|
|
47
|
+
"summary": "Provides runtime.json-rest-api and exports focused resource/query helpers, including server-only row policies."
|
|
48
|
+
}
|
|
49
|
+
]
|
|
50
|
+
}
|
|
51
|
+
}
|
|
15
52
|
}
|
|
16
53
|
}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { defineProvider } from "@jskit-ai/kernel/shared/capabilities";
|
|
2
|
+
import { createJsonRestApiHost } from "./jsonRestApiHost.js";
|
|
3
|
+
|
|
4
|
+
const JsonRestApiProvider = defineProvider({
|
|
5
|
+
id: "runtime.json-rest-api",
|
|
6
|
+
requires: {
|
|
7
|
+
database: "runtime.database"
|
|
8
|
+
},
|
|
9
|
+
provides: {
|
|
10
|
+
jsonRestApi: "runtime.json-rest-api"
|
|
11
|
+
},
|
|
12
|
+
async setup({ database }) {
|
|
13
|
+
return {
|
|
14
|
+
jsonRestApi: await createJsonRestApiHost({ knex: database.knex })
|
|
15
|
+
};
|
|
16
|
+
}
|
|
17
|
+
});
|
|
18
|
+
|
|
19
|
+
export { JsonRestApiProvider };
|
|
@@ -11,15 +11,13 @@ import {
|
|
|
11
11
|
normalizeRecordId,
|
|
12
12
|
normalizeUniqueTextList
|
|
13
13
|
} from "@jskit-ai/kernel/shared/support/normalize";
|
|
14
|
-
import { resolveCrudResourceScopeName } from "@jskit-ai/
|
|
14
|
+
import { resolveCrudResourceScopeName } from "@jskit-ai/resource-crud-core/shared/crudLookup";
|
|
15
15
|
import {
|
|
16
16
|
normalizeJsonApiFieldList,
|
|
17
17
|
normalizeJsonApiFieldsets
|
|
18
18
|
} from "@jskit-ai/kernel/shared/support/jsonApiFieldsets";
|
|
19
19
|
import { AppError } from "@jskit-ai/kernel/server/runtime/errors";
|
|
20
20
|
|
|
21
|
-
const INTERNAL_JSON_REST_API = "internal.json-rest-api";
|
|
22
|
-
|
|
23
21
|
const JSON_REST_AUTOFILTER_PRESETS = Object.freeze({
|
|
24
22
|
public: Object.freeze([]),
|
|
25
23
|
workspace: Object.freeze([
|
|
@@ -108,38 +106,6 @@ function cloneJsonRestResourceValue(value, { writeSerializers = {} } = {}) {
|
|
|
108
106
|
return next;
|
|
109
107
|
}
|
|
110
108
|
|
|
111
|
-
function applyJsonRestStorageColumns(scopeOptions = {}) {
|
|
112
|
-
const schema = normalizeJsonRestObject(scopeOptions.schema);
|
|
113
|
-
for (const [fieldName, fieldDefinition] of Object.entries(schema)) {
|
|
114
|
-
if (!isPlainJsonRestObject(fieldDefinition)) {
|
|
115
|
-
continue;
|
|
116
|
-
}
|
|
117
|
-
|
|
118
|
-
const actualField = normalizeJsonRestText(fieldDefinition.actualField);
|
|
119
|
-
if (!actualField) {
|
|
120
|
-
continue;
|
|
121
|
-
}
|
|
122
|
-
|
|
123
|
-
const storage = normalizeJsonRestObject(fieldDefinition.storage);
|
|
124
|
-
const storageColumn = normalizeJsonRestText(storage.column);
|
|
125
|
-
if (storage.virtual === true) {
|
|
126
|
-
throw new Error(
|
|
127
|
-
`json-rest-api schema field "${fieldName}" cannot define actualField when storage.virtual is true.`
|
|
128
|
-
);
|
|
129
|
-
}
|
|
130
|
-
if (storageColumn && storageColumn !== actualField) {
|
|
131
|
-
throw new Error(
|
|
132
|
-
`json-rest-api schema field "${fieldName}" actualField and storage.column must match.`
|
|
133
|
-
);
|
|
134
|
-
}
|
|
135
|
-
|
|
136
|
-
fieldDefinition.storage = {
|
|
137
|
-
...storage,
|
|
138
|
-
column: actualField
|
|
139
|
-
};
|
|
140
|
-
}
|
|
141
|
-
}
|
|
142
|
-
|
|
143
109
|
function resolveCanonicalCalendarDate(value) {
|
|
144
110
|
if (value instanceof Date) {
|
|
145
111
|
return Number.isNaN(value.getTime())
|
|
@@ -709,7 +675,6 @@ function createJsonRestResourceScopeOptions(
|
|
|
709
675
|
const scopeOptions = cloneJsonRestResourceValue(resource, {
|
|
710
676
|
writeSerializers: normalizeJsonRestObject(writeSerializers)
|
|
711
677
|
});
|
|
712
|
-
applyJsonRestStorageColumns(scopeOptions);
|
|
713
678
|
applyJsonRestCalendarDateWriteSerializers(scopeOptions);
|
|
714
679
|
if (isPlainJsonRestObject(searchSchema)) {
|
|
715
680
|
scopeOptions.searchSchema = {
|
|
@@ -870,23 +835,7 @@ async function createJsonRestApiHost({ knex }) {
|
|
|
870
835
|
return api;
|
|
871
836
|
}
|
|
872
837
|
|
|
873
|
-
async function registerJsonRestApiHost(app) {
|
|
874
|
-
if (!app || typeof app.instance !== "function" || typeof app.make !== "function" || typeof app.has !== "function") {
|
|
875
|
-
throw new Error("registerJsonRestApiHost requires application instance()/make()/has().");
|
|
876
|
-
}
|
|
877
|
-
|
|
878
|
-
if (app.has(INTERNAL_JSON_REST_API)) {
|
|
879
|
-
return app.make(INTERNAL_JSON_REST_API);
|
|
880
|
-
}
|
|
881
|
-
|
|
882
|
-
const knex = app.make("jskit.database.knex");
|
|
883
|
-
const api = await createJsonRestApiHost({ knex });
|
|
884
|
-
app.instance(INTERNAL_JSON_REST_API, api);
|
|
885
|
-
return api;
|
|
886
|
-
}
|
|
887
|
-
|
|
888
838
|
export {
|
|
889
|
-
INTERNAL_JSON_REST_API,
|
|
890
839
|
JSON_REST_AUTOFILTER_PRESETS,
|
|
891
840
|
addResourceIfMissing,
|
|
892
841
|
buildJsonRestQueryParams,
|
|
@@ -900,6 +849,5 @@ export {
|
|
|
900
849
|
returnBadRequestWhenJsonRestFieldsetInvalid,
|
|
901
850
|
resolveWorkspaceScopeValue,
|
|
902
851
|
resolveUserScopeValue,
|
|
903
|
-
createJsonRestApiHost
|
|
904
|
-
registerJsonRestApiHost
|
|
852
|
+
createJsonRestApiHost
|
|
905
853
|
};
|
|
@@ -6,7 +6,6 @@ import { normalizeRecordId } from "@jskit-ai/kernel/shared/support/normalize";
|
|
|
6
6
|
import { RestApiFieldsetError } from "json-rest-api";
|
|
7
7
|
|
|
8
8
|
import {
|
|
9
|
-
INTERNAL_JSON_REST_API,
|
|
10
9
|
addResourceIfMissing,
|
|
11
10
|
buildJsonRestQueryParams,
|
|
12
11
|
createJsonApiInputRecord,
|
|
@@ -16,13 +15,12 @@ import {
|
|
|
16
15
|
createJsonRestApiHost,
|
|
17
16
|
extractJsonRestCollectionRows,
|
|
18
17
|
isJsonRestResourceMissingError,
|
|
19
|
-
registerJsonRestApiHost,
|
|
20
18
|
returnNullWhenJsonRestResourceMissing,
|
|
21
19
|
returnBadRequestWhenJsonRestFieldsetInvalid,
|
|
22
20
|
resolveWorkspaceScopeValue,
|
|
23
21
|
resolveUserScopeValue
|
|
24
22
|
} from "../src/server/jsonRestApiHost.js";
|
|
25
|
-
import {
|
|
23
|
+
import { JsonRestApiProvider } from "../src/server/JsonRestApiProvider.js";
|
|
26
24
|
|
|
27
25
|
test("package exports include explicit server jsonRestApiHost entrypoint only", async () => {
|
|
28
26
|
const packageJson = JSON.parse(await readFile(new URL("../package.json", import.meta.url), "utf8"));
|
|
@@ -32,13 +30,12 @@ test("package exports include explicit server jsonRestApiHost entrypoint only",
|
|
|
32
30
|
assert.equal(packageJson.dependencies?.["json-rest-api"], "^1.0.27");
|
|
33
31
|
});
|
|
34
32
|
|
|
35
|
-
test("server jsonRestApiHost entrypoint
|
|
33
|
+
test("server jsonRestApiHost entrypoint exposes only the focused host API", async () => {
|
|
36
34
|
const hostModule = await import("../src/server/jsonRestApiHost.js");
|
|
37
35
|
assert.equal(Object.hasOwn(hostModule, "simplifyJsonApiDocument"), false);
|
|
38
36
|
});
|
|
39
37
|
|
|
40
38
|
test("server entrypoint exports shared host helpers", () => {
|
|
41
|
-
assert.equal(INTERNAL_JSON_REST_API, "internal.json-rest-api");
|
|
42
39
|
assert.equal(typeof addResourceIfMissing, "function");
|
|
43
40
|
assert.equal(typeof buildJsonRestQueryParams, "function");
|
|
44
41
|
assert.equal(typeof createJsonApiInputRecord, "function");
|
|
@@ -48,12 +45,13 @@ test("server entrypoint exports shared host helpers", () => {
|
|
|
48
45
|
assert.equal(typeof createJsonRestApiHost, "function");
|
|
49
46
|
assert.equal(typeof extractJsonRestCollectionRows, "function");
|
|
50
47
|
assert.equal(typeof isJsonRestResourceMissingError, "function");
|
|
51
|
-
assert.equal(typeof registerJsonRestApiHost, "function");
|
|
52
48
|
assert.equal(typeof returnNullWhenJsonRestResourceMissing, "function");
|
|
53
49
|
assert.equal(typeof returnBadRequestWhenJsonRestFieldsetInvalid, "function");
|
|
54
50
|
assert.equal(typeof resolveWorkspaceScopeValue, "function");
|
|
55
51
|
assert.equal(typeof resolveUserScopeValue, "function");
|
|
56
|
-
assert.equal(
|
|
52
|
+
assert.equal(JsonRestApiProvider.id, "runtime.json-rest-api");
|
|
53
|
+
assert.deepEqual(JsonRestApiProvider.requires, { database: "runtime.database" });
|
|
54
|
+
assert.deepEqual(JsonRestApiProvider.provides, { jsonRestApi: "runtime.json-rest-api" });
|
|
57
55
|
});
|
|
58
56
|
|
|
59
57
|
test("createJsonRestContext returns a mutable clone for frozen JSKIT execution context", () => {
|
|
@@ -460,48 +458,6 @@ test("createJsonRestResourceScopeOptions clones canonical resource metadata and
|
|
|
460
458
|
assert.equal(source.schema.createdAt.indexed, undefined);
|
|
461
459
|
});
|
|
462
460
|
|
|
463
|
-
test("createJsonRestResourceScopeOptions maps resource actualField values to storage columns", () => {
|
|
464
|
-
const resource = Object.freeze({
|
|
465
|
-
namespace: "products",
|
|
466
|
-
schema: Object.freeze({
|
|
467
|
-
price1: Object.freeze({ type: "number", actualField: "price_1" }),
|
|
468
|
-
price2: Object.freeze({
|
|
469
|
-
type: "number",
|
|
470
|
-
actualField: "price_2",
|
|
471
|
-
storage: Object.freeze({ writeSerializer: "decimal" })
|
|
472
|
-
})
|
|
473
|
-
}),
|
|
474
|
-
searchSchema: Object.freeze({
|
|
475
|
-
minimumPrice: Object.freeze({ type: "number", actualField: "price_1", filterOperator: ">=" })
|
|
476
|
-
})
|
|
477
|
-
});
|
|
478
|
-
const decimalSerializer = (value) => value;
|
|
479
|
-
|
|
480
|
-
const result = createJsonRestResourceScopeOptions(resource, {
|
|
481
|
-
writeSerializers: { decimal: decimalSerializer }
|
|
482
|
-
});
|
|
483
|
-
|
|
484
|
-
assert.equal(result.schema.price1.storage.column, "price_1");
|
|
485
|
-
assert.equal(result.schema.price2.storage.column, "price_2");
|
|
486
|
-
assert.equal(result.schema.price2.storage.serialize, decimalSerializer);
|
|
487
|
-
assert.equal(result.searchSchema.minimumPrice.actualField, "price_1");
|
|
488
|
-
assert.equal(result.searchSchema.minimumPrice.storage, undefined);
|
|
489
|
-
assert.equal(resource.schema.price1.storage, undefined);
|
|
490
|
-
|
|
491
|
-
assert.throws(
|
|
492
|
-
() => createJsonRestResourceScopeOptions({
|
|
493
|
-
schema: {
|
|
494
|
-
price1: {
|
|
495
|
-
type: "number",
|
|
496
|
-
actualField: "price_1",
|
|
497
|
-
storage: { column: "price1" }
|
|
498
|
-
}
|
|
499
|
-
}
|
|
500
|
-
}),
|
|
501
|
-
/actualField and storage\.column must match/
|
|
502
|
-
);
|
|
503
|
-
});
|
|
504
|
-
|
|
505
461
|
test("createJsonRestResourceScopeOptions maps server query projections into json-rest-api queryFields", () => {
|
|
506
462
|
const select = ({ knex }) => knex.raw("1");
|
|
507
463
|
const resource = {
|
package/package.descriptor.mjs
DELETED
|
@@ -1,60 +0,0 @@
|
|
|
1
|
-
export default Object.freeze({
|
|
2
|
-
packageVersion: 1,
|
|
3
|
-
packageId: "@jskit-ai/json-rest-api-core",
|
|
4
|
-
version: "0.1.92",
|
|
5
|
-
kind: "runtime",
|
|
6
|
-
description: "Shared internal json-rest-api host runtime with autofilter, query-projection, and row-policy support.",
|
|
7
|
-
dependsOn: [
|
|
8
|
-
"@jskit-ai/database-runtime",
|
|
9
|
-
"@jskit-ai/kernel"
|
|
10
|
-
],
|
|
11
|
-
capabilities: {
|
|
12
|
-
provides: [
|
|
13
|
-
"json-rest-api.core"
|
|
14
|
-
],
|
|
15
|
-
requires: [
|
|
16
|
-
"runtime.database"
|
|
17
|
-
]
|
|
18
|
-
},
|
|
19
|
-
runtime: {
|
|
20
|
-
server: {
|
|
21
|
-
providers: [
|
|
22
|
-
{
|
|
23
|
-
entrypoint: "src/server/JsonRestApiCoreServiceProvider.js",
|
|
24
|
-
export: "JsonRestApiCoreServiceProvider"
|
|
25
|
-
}
|
|
26
|
-
]
|
|
27
|
-
},
|
|
28
|
-
client: {
|
|
29
|
-
providers: []
|
|
30
|
-
}
|
|
31
|
-
},
|
|
32
|
-
metadata: {
|
|
33
|
-
apiSummary: {
|
|
34
|
-
surfaces: [
|
|
35
|
-
{
|
|
36
|
-
subpath: "./server",
|
|
37
|
-
summary: "Exports the shared internal json-rest-api host token and resource registration helpers, including server-only row policies."
|
|
38
|
-
}
|
|
39
|
-
],
|
|
40
|
-
containerTokens: {
|
|
41
|
-
server: [
|
|
42
|
-
"internal.json-rest-api"
|
|
43
|
-
],
|
|
44
|
-
client: []
|
|
45
|
-
}
|
|
46
|
-
}
|
|
47
|
-
},
|
|
48
|
-
mutations: {
|
|
49
|
-
dependencies: {
|
|
50
|
-
runtime: {},
|
|
51
|
-
dev: {}
|
|
52
|
-
},
|
|
53
|
-
packageJson: {
|
|
54
|
-
scripts: {}
|
|
55
|
-
},
|
|
56
|
-
procfile: {},
|
|
57
|
-
files: [],
|
|
58
|
-
text: []
|
|
59
|
-
}
|
|
60
|
-
});
|
|
@@ -1,13 +0,0 @@
|
|
|
1
|
-
import { registerJsonRestApiHost } from "./jsonRestApiHost.js";
|
|
2
|
-
|
|
3
|
-
class JsonRestApiCoreServiceProvider {
|
|
4
|
-
static id = "json-rest-api.core";
|
|
5
|
-
|
|
6
|
-
static dependsOn = ["runtime.database"];
|
|
7
|
-
|
|
8
|
-
async boot(app) {
|
|
9
|
-
await registerJsonRestApiHost(app);
|
|
10
|
-
}
|
|
11
|
-
}
|
|
12
|
-
|
|
13
|
-
export { JsonRestApiCoreServiceProvider };
|