json-rest-api 1.0.13 → 1.0.15
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/connectors_ideas/fastify.js +66 -68
- package/connectors_ideas/koa-plugin.js +50 -51
- package/eslint.config.js +13 -0
- package/examples/url-override-example.js +63 -63
- package/index.js +13 -13
- package/lib/enhanced-logger.js +51 -51
- package/lib/error-formatter.js +61 -61
- package/lib/rest-api-errors.js +28 -28
- package/package.json +9 -5
- package/plugins/core/bulk-operations-plugin.js +142 -145
- package/plugins/core/connectors/express-plugin.js +210 -217
- package/plugins/core/connectors/lib/busboy-detector.js +84 -84
- package/plugins/core/connectors/lib/formidable-detector.js +50 -50
- package/plugins/core/connectors/lib/request-helpers.js +74 -74
- package/plugins/core/file-handling-plugin.js +125 -125
- package/plugins/core/lib/anyapi/anyapi-registry.js +254 -254
- package/plugins/core/lib/anyapi/query/anyapi-query-adapter.js +287 -287
- package/plugins/core/lib/anyapi/schema-utils.js +101 -101
- package/plugins/core/lib/anyapi/utils/descriptor-helpers.js +41 -41
- package/plugins/core/lib/dbTablesOperations.js +134 -135
- package/plugins/core/lib/fractional-positioning.js +74 -76
- package/plugins/core/lib/querying/knex-cross-table-search.js +320 -320
- package/plugins/core/lib/querying/knex-json-api-transformers-querying.js +144 -144
- package/plugins/core/lib/querying/knex-pagination-helpers.js +164 -164
- package/plugins/core/lib/querying/knex-process-includes.js +50 -50
- package/plugins/core/lib/querying/knex-query-helpers-base.js +31 -31
- package/plugins/core/lib/querying/knex-query-helpers.js +451 -452
- package/plugins/core/lib/querying/knex-relationship-includes.js +1160 -1170
- package/plugins/core/lib/querying/knex-window-queries.js +89 -89
- package/plugins/core/lib/querying/url-helpers.js +35 -35
- package/plugins/core/lib/querying-writing/compile-schemas.js +97 -98
- package/plugins/core/lib/querying-writing/connectors-query-parser.js +31 -31
- package/plugins/core/lib/querying-writing/database-capabilities.js +94 -94
- package/plugins/core/lib/querying-writing/database-value-normalizers.js +76 -76
- package/plugins/core/lib/querying-writing/default-data-helpers.js +27 -27
- package/plugins/core/lib/querying-writing/field-utils.js +44 -42
- package/plugins/core/lib/querying-writing/knex-constants.js +15 -16
- package/plugins/core/lib/querying-writing/knex-field-helpers.js +117 -115
- package/plugins/core/lib/querying-writing/knex-json-api-transformers.js +41 -41
- package/plugins/core/lib/querying-writing/payload-validators.js +275 -275
- package/plugins/core/lib/querying-writing/schema-helpers.js +129 -129
- package/plugins/core/lib/querying-writing/scope-validations.js +143 -146
- package/plugins/core/lib/querying-writing/simplified-helpers.js +133 -129
- package/plugins/core/lib/storage/storage-adapter.js +68 -68
- package/plugins/core/lib/writing/knex-json-api-transformers-writing.js +31 -31
- package/plugins/core/lib/writing/many-to-many-manipulations.js +81 -81
- package/plugins/core/lib/writing/relationship-processor.js +58 -58
- package/plugins/core/rest-api-access.js +8 -8
- package/plugins/core/rest-api-anyapi-knex-plugin.js +920 -920
- package/plugins/core/rest-api-cors-plugin.js +170 -171
- package/plugins/core/rest-api-knex-plugin.js +482 -493
- package/plugins/core/rest-api-multihome-plugin.js +247 -251
- package/plugins/core/rest-api-plugin-hooks/compile-resource-schemas.js +5 -5
- package/plugins/core/rest-api-plugin-hooks/register-relationship-routes.js +20 -21
- package/plugins/core/rest-api-plugin-hooks/register-scope-routes.js +44 -44
- package/plugins/core/rest-api-plugin-hooks/turn-scope-init-into-vars.js +23 -23
- package/plugins/core/rest-api-plugin-hooks/validate-include-configurations.js +15 -15
- package/plugins/core/rest-api-plugin-methods/add-route.js +9 -9
- package/plugins/core/rest-api-plugin-methods/check-permissions.js +5 -6
- package/plugins/core/rest-api-plugin-methods/common.js +295 -297
- package/plugins/core/rest-api-plugin-methods/delete-relationship.js +35 -37
- package/plugins/core/rest-api-plugin-methods/delete.js +57 -59
- package/plugins/core/rest-api-plugin-methods/enrich-attributes.js +172 -171
- package/plugins/core/rest-api-plugin-methods/get-related.js +96 -96
- package/plugins/core/rest-api-plugin-methods/get-relationship.js +16 -18
- package/plugins/core/rest-api-plugin-methods/get.js +86 -86
- package/plugins/core/rest-api-plugin-methods/patch-relationship.js +16 -17
- package/plugins/core/rest-api-plugin-methods/patch.js +63 -64
- package/plugins/core/rest-api-plugin-methods/post-relationship.js +54 -55
- package/plugins/core/rest-api-plugin-methods/post.js +61 -62
- package/plugins/core/rest-api-plugin-methods/put.js +86 -87
- package/plugins/core/rest-api-plugin-methods/query.js +88 -88
- package/plugins/core/rest-api-plugin-methods/release.js +5 -6
- package/plugins/core/rest-api-plugin.js +76 -78
- package/plugins/core/rest-api-positioning-plugin.js +251 -252
- package/plugins/core/socketio-plugin.js +240 -236
- package/plugins/storage/local-storage.js +103 -103
- package/plugins/storage/s3-storage.js +41 -42
- package/quickTest.js +37 -37
- package/scripts/debug-anyapi-review-filter.mjs +18 -18
- package/scripts/inspect-anyapi-descriptor-country.mjs +10 -10
- package/scripts/inspect-anyapi-descriptor.mjs +10 -10
- package/scripts/run-docs.js +112 -113
- package/test-debug.js +28 -28
- package/tests/TEST_TEMPLATE.test.js +51 -51
- package/tests/anyapi-basic.test.js +42 -42
- package/tests/anyapi-cursor-pagination.test.js +48 -48
- package/tests/bulk-operations.test.js +208 -208
- package/tests/computed-fields.test.js +204 -204
- package/tests/cors.test.js +412 -413
- package/tests/curl.test.js +275 -276
- package/tests/custom-idproperty-relationships.test.js +266 -266
- package/tests/field-getters.test.js +132 -132
- package/tests/field-setters.test.js +110 -110
- package/tests/fixtures/api-configs.js +699 -699
- package/tests/helpers/storage-mode.js +32 -32
- package/tests/helpers/test-utils.js +76 -76
- package/tests/include-depth-validation.test.js +76 -76
- package/tests/includes.test.js +145 -145
- package/tests/multihome.test.js +175 -175
- package/tests/nested-includes.test.js +255 -255
- package/tests/pagination-cursor-multifield.test.js +164 -164
- package/tests/pagination-enhanced.test.js +225 -225
- package/tests/polymorphic-relationships.test.js +96 -96
- package/tests/polymorphic-simple.test.js +44 -44
- package/tests/positioning-advanced.test.js +226 -226
- package/tests/positioning-extended.test.js +399 -399
- package/tests/positioning-multifilter.test.js +204 -204
- package/tests/positioning.test.js +266 -266
- package/tests/queries.test.js +184 -184
- package/tests/query-limits.test.js +154 -155
- package/tests/relationship-endpoints.test.js +127 -127
- package/tests/relationships.test.js +178 -179
- package/tests/rest-api-access.test.js +86 -86
- package/tests/rest-api.test.js +103 -103
- package/tests/searchschema-merge.test.js +93 -93
- package/tests/socketio.test.js +326 -326
- package/tests/virtual-fields.test.js +164 -164
|
@@ -1,25 +1,25 @@
|
|
|
1
|
-
import knexLib from 'knex'
|
|
2
|
-
import { createCustomIdPropertyApi } from '../tests/fixtures/api-configs.js'
|
|
3
|
-
import { createJsonApiDocument } from '../tests/helpers/test-utils.js'
|
|
1
|
+
import knexLib from 'knex'
|
|
2
|
+
import { createCustomIdPropertyApi } from '../tests/fixtures/api-configs.js'
|
|
3
|
+
import { createJsonApiDocument } from '../tests/helpers/test-utils.js'
|
|
4
4
|
|
|
5
|
-
async function run() {
|
|
6
|
-
const knex = knexLib({ client: 'better-sqlite3', connection: { filename: ':memory:' }, useNullAsDefault: true })
|
|
7
|
-
const api = await createCustomIdPropertyApi(knex)
|
|
5
|
+
async function run () {
|
|
6
|
+
const knex = knexLib({ client: 'better-sqlite3', connection: { filename: ':memory:' }, useNullAsDefault: true })
|
|
7
|
+
const api = await createCustomIdPropertyApi(knex)
|
|
8
8
|
|
|
9
9
|
const country = await api.resources.countries.post({
|
|
10
10
|
inputRecord: createJsonApiDocument('countries', { name: 'USA', code: 'US' })
|
|
11
|
-
})
|
|
11
|
+
})
|
|
12
12
|
|
|
13
13
|
const book = await api.resources.books.post({
|
|
14
14
|
inputRecord: createJsonApiDocument('books',
|
|
15
15
|
{ title: 'Test Book' },
|
|
16
16
|
{ country: { data: { type: 'countries', id: country.data.id } } }
|
|
17
17
|
)
|
|
18
|
-
})
|
|
18
|
+
})
|
|
19
19
|
|
|
20
20
|
const author = await api.resources.authors.post({
|
|
21
21
|
inputRecord: createJsonApiDocument('authors', { name: 'Author' })
|
|
22
|
-
})
|
|
22
|
+
})
|
|
23
23
|
|
|
24
24
|
await api.resources.reviews.post({
|
|
25
25
|
inputRecord: createJsonApiDocument('reviews', {
|
|
@@ -30,7 +30,7 @@ async function run() {
|
|
|
30
30
|
reviewable_type: 'books',
|
|
31
31
|
reviewable_id: book.data.id
|
|
32
32
|
})
|
|
33
|
-
})
|
|
33
|
+
})
|
|
34
34
|
|
|
35
35
|
await api.resources.reviews.post({
|
|
36
36
|
inputRecord: createJsonApiDocument('reviews', {
|
|
@@ -41,23 +41,23 @@ async function run() {
|
|
|
41
41
|
reviewable_type: 'authors',
|
|
42
42
|
reviewable_id: author.data.id
|
|
43
43
|
})
|
|
44
|
-
})
|
|
44
|
+
})
|
|
45
45
|
|
|
46
46
|
try {
|
|
47
47
|
const res = await api.resources.reviews.query({
|
|
48
48
|
queryParams: { filters: { reviewable_type: 'books' } }
|
|
49
|
-
})
|
|
50
|
-
console.log('Query succeeded with rows:', res.data.length)
|
|
49
|
+
})
|
|
50
|
+
console.log('Query succeeded with rows:', res.data.length)
|
|
51
51
|
} catch (error) {
|
|
52
|
-
console.error('Query failed:', error)
|
|
52
|
+
console.error('Query failed:', error)
|
|
53
53
|
if (error?.sql) {
|
|
54
|
-
console.error('SQL:', error.sql)
|
|
54
|
+
console.error('SQL:', error.sql)
|
|
55
55
|
}
|
|
56
56
|
}
|
|
57
57
|
|
|
58
|
-
await knex.destroy()
|
|
58
|
+
await knex.destroy()
|
|
59
59
|
}
|
|
60
60
|
|
|
61
61
|
run().catch((err) => {
|
|
62
|
-
console.error('Unexpected failure:', err)
|
|
63
|
-
})
|
|
62
|
+
console.error('Unexpected failure:', err)
|
|
63
|
+
})
|
|
@@ -1,19 +1,19 @@
|
|
|
1
|
-
import knexLib from 'knex'
|
|
2
|
-
import { createCustomIdPropertyApi } from '../tests/fixtures/api-configs.js'
|
|
1
|
+
import knexLib from 'knex'
|
|
2
|
+
import { createCustomIdPropertyApi } from '../tests/fixtures/api-configs.js'
|
|
3
3
|
|
|
4
|
-
async function run() {
|
|
5
|
-
const knex = knexLib({ client: 'better-sqlite3', connection: { filename: ':memory:' }, useNullAsDefault: true })
|
|
6
|
-
const api = await createCustomIdPropertyApi(knex)
|
|
7
|
-
const descriptor = await api.anyapi.registry.getDescriptor('default', 'countries')
|
|
4
|
+
async function run () {
|
|
5
|
+
const knex = knexLib({ client: 'better-sqlite3', connection: { filename: ':memory:' }, useNullAsDefault: true })
|
|
6
|
+
const api = await createCustomIdPropertyApi(knex)
|
|
7
|
+
const descriptor = await api.anyapi.registry.getDescriptor('default', 'countries')
|
|
8
8
|
console.log(JSON.stringify({
|
|
9
9
|
idProperty: descriptor.idProperty,
|
|
10
10
|
fields: descriptor.fields,
|
|
11
11
|
canonicalFieldMap: descriptor.canonicalFieldMap,
|
|
12
12
|
reverseAttributes: descriptor.reverseAttributes,
|
|
13
|
-
}, null, 2))
|
|
14
|
-
await knex.destroy()
|
|
13
|
+
}, null, 2))
|
|
14
|
+
await knex.destroy()
|
|
15
15
|
}
|
|
16
16
|
|
|
17
17
|
run().catch((err) => {
|
|
18
|
-
console.error('Failed to inspect descriptor', err)
|
|
19
|
-
})
|
|
18
|
+
console.error('Failed to inspect descriptor', err)
|
|
19
|
+
})
|
|
@@ -1,19 +1,19 @@
|
|
|
1
|
-
import knexLib from 'knex'
|
|
2
|
-
import { createCustomIdPropertyApi } from '../tests/fixtures/api-configs.js'
|
|
1
|
+
import knexLib from 'knex'
|
|
2
|
+
import { createCustomIdPropertyApi } from '../tests/fixtures/api-configs.js'
|
|
3
3
|
|
|
4
|
-
async function run() {
|
|
5
|
-
const knex = knexLib({ client: 'better-sqlite3', connection: { filename: ':memory:' }, useNullAsDefault: true })
|
|
6
|
-
const api = await createCustomIdPropertyApi(knex)
|
|
7
|
-
const descriptor = await api.anyapi.registry.getDescriptor('default', 'reviews')
|
|
4
|
+
async function run () {
|
|
5
|
+
const knex = knexLib({ client: 'better-sqlite3', connection: { filename: ':memory:' }, useNullAsDefault: true })
|
|
6
|
+
const api = await createCustomIdPropertyApi(knex)
|
|
7
|
+
const descriptor = await api.anyapi.registry.getDescriptor('default', 'reviews')
|
|
8
8
|
console.log(JSON.stringify({
|
|
9
9
|
idProperty: descriptor.idProperty,
|
|
10
10
|
fields: descriptor.fields,
|
|
11
11
|
canonicalFieldMap: descriptor.canonicalFieldMap,
|
|
12
12
|
reverseAttributes: descriptor.reverseAttributes,
|
|
13
|
-
}, null, 2))
|
|
14
|
-
await knex.destroy()
|
|
13
|
+
}, null, 2))
|
|
14
|
+
await knex.destroy()
|
|
15
15
|
}
|
|
16
16
|
|
|
17
17
|
run().catch((err) => {
|
|
18
|
-
console.error('Failed to inspect descriptor', err)
|
|
19
|
-
})
|
|
18
|
+
console.error('Failed to inspect descriptor', err)
|
|
19
|
+
})
|
package/scripts/run-docs.js
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
/**
|
|
4
4
|
* Run the documentation site
|
|
5
|
-
*
|
|
5
|
+
*
|
|
6
6
|
* This script:
|
|
7
7
|
* 1. Syncs documentation files
|
|
8
8
|
* 2. Builds the Jekyll site
|
|
@@ -10,129 +10,128 @@
|
|
|
10
10
|
* 4. Opens the browser
|
|
11
11
|
*/
|
|
12
12
|
|
|
13
|
-
import { spawn } from 'child_process'
|
|
14
|
-
import { promises as fs } from 'fs'
|
|
15
|
-
import path from 'path'
|
|
16
|
-
import { fileURLToPath } from 'url'
|
|
13
|
+
import { spawn } from 'child_process'
|
|
14
|
+
import { promises as fs } from 'fs'
|
|
15
|
+
import path from 'path'
|
|
16
|
+
import { fileURLToPath } from 'url'
|
|
17
17
|
|
|
18
|
-
const __filename = fileURLToPath(import.meta.url)
|
|
19
|
-
const __dirname = path.dirname(__filename)
|
|
20
|
-
const projectRoot = path.join(__dirname, '..')
|
|
18
|
+
const __filename = fileURLToPath(import.meta.url)
|
|
19
|
+
const __dirname = path.dirname(__filename)
|
|
20
|
+
const projectRoot = path.join(__dirname, '..')
|
|
21
21
|
|
|
22
22
|
// Delay before opening browser (milliseconds)
|
|
23
|
-
const BROWSER_DELAY = 3000
|
|
23
|
+
const BROWSER_DELAY = 3000
|
|
24
24
|
|
|
25
25
|
// Site URLs
|
|
26
|
-
const LOCAL_URL = 'http://localhost:4000/json-rest-api/'
|
|
27
|
-
const GITHUB_PAGES_URL = 'https://mobily-enterprises.github.io/json-rest-api/'
|
|
28
|
-
|
|
29
|
-
async function runCommand(command, args, options = {}) {
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
26
|
+
const LOCAL_URL = 'http://localhost:4000/json-rest-api/'
|
|
27
|
+
const GITHUB_PAGES_URL = 'https://mobily-enterprises.github.io/json-rest-api/'
|
|
28
|
+
|
|
29
|
+
async function runCommand (command, args, options = {}) {
|
|
30
|
+
return new Promise((resolve, reject) => {
|
|
31
|
+
const proc = spawn(command, args, {
|
|
32
|
+
stdio: 'inherit',
|
|
33
|
+
shell: true,
|
|
34
|
+
...options
|
|
35
|
+
})
|
|
36
|
+
|
|
37
|
+
proc.on('error', reject)
|
|
38
|
+
proc.on('exit', (code) => {
|
|
39
|
+
if (code === 0) {
|
|
40
|
+
resolve()
|
|
41
|
+
} else {
|
|
42
|
+
reject(new Error(`Command failed with code ${code}`))
|
|
43
|
+
}
|
|
44
|
+
})
|
|
45
|
+
})
|
|
46
46
|
}
|
|
47
47
|
|
|
48
|
-
async function openBrowser(url) {
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
48
|
+
async function openBrowser (url) {
|
|
49
|
+
const platform = process.platform
|
|
50
|
+
let command
|
|
51
|
+
|
|
52
|
+
if (platform === 'darwin') {
|
|
53
|
+
command = 'open'
|
|
54
|
+
} else if (platform === 'win32') {
|
|
55
|
+
command = 'start'
|
|
56
|
+
} else {
|
|
57
|
+
// Linux
|
|
58
|
+
command = 'xdg-open'
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
try {
|
|
62
|
+
await runCommand(command, [url])
|
|
63
|
+
console.log(`\n🌐 Opened browser at ${url}`)
|
|
64
|
+
} catch (err) {
|
|
65
|
+
console.log(`\n💡 Visit ${url} in your browser`)
|
|
66
|
+
}
|
|
67
67
|
}
|
|
68
68
|
|
|
69
|
-
async function main() {
|
|
70
|
-
|
|
71
|
-
|
|
69
|
+
async function main () {
|
|
70
|
+
console.log('📚 Starting documentation site...\n')
|
|
71
|
+
|
|
72
|
+
try {
|
|
73
|
+
// Step 1: There is no step 1
|
|
74
|
+
|
|
75
|
+
// Step 2: Install Jekyll dependencies if needed
|
|
76
|
+
const bundleLockPath = path.join(projectRoot, 'docs', 'Gemfile.lock')
|
|
72
77
|
try {
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
} catch {
|
|
80
|
-
console.log('\n2️⃣ Installing Jekyll dependencies...');
|
|
81
|
-
await runCommand('bundle', ['install'], {
|
|
82
|
-
cwd: path.join(projectRoot, 'docs')
|
|
83
|
-
});
|
|
84
|
-
}
|
|
85
|
-
|
|
86
|
-
// Step 3: Start Jekyll server in background
|
|
87
|
-
console.log('\n3️⃣ Starting Jekyll server...');
|
|
88
|
-
const jekyll = spawn('bundle', ['exec', 'jekyll', 'serve', '--watch'], {
|
|
89
|
-
cwd: path.join(projectRoot, 'docs'),
|
|
90
|
-
stdio: 'pipe',
|
|
91
|
-
shell: true
|
|
92
|
-
});
|
|
93
|
-
|
|
94
|
-
// Handle server output
|
|
95
|
-
jekyll.stdout.on('data', (data) => {
|
|
96
|
-
const output = data.toString();
|
|
97
|
-
process.stdout.write(output);
|
|
98
|
-
|
|
99
|
-
// Open browser when server is ready
|
|
100
|
-
if (output.includes('Server running') || output.includes('Server address:')) {
|
|
101
|
-
setTimeout(() => openBrowser(LOCAL_URL), 1000);
|
|
102
|
-
}
|
|
103
|
-
});
|
|
104
|
-
|
|
105
|
-
jekyll.stderr.on('data', (data) => {
|
|
106
|
-
process.stderr.write(data);
|
|
107
|
-
});
|
|
108
|
-
|
|
109
|
-
// Handle shutdown
|
|
110
|
-
process.on('SIGINT', () => {
|
|
111
|
-
console.log('\n\n👋 Shutting down Jekyll server...');
|
|
112
|
-
jekyll.kill();
|
|
113
|
-
process.exit(0);
|
|
114
|
-
});
|
|
115
|
-
|
|
116
|
-
jekyll.on('error', (err) => {
|
|
117
|
-
console.error('❌ Jekyll server error:', err);
|
|
118
|
-
process.exit(1);
|
|
119
|
-
});
|
|
120
|
-
|
|
121
|
-
jekyll.on('exit', (code) => {
|
|
122
|
-
if (code !== 0 && code !== null) {
|
|
123
|
-
console.error(`❌ Jekyll server exited with code ${code}`);
|
|
124
|
-
process.exit(code);
|
|
125
|
-
}
|
|
126
|
-
});
|
|
127
|
-
|
|
128
|
-
// Wait a bit then try to open browser anyway (in case we missed the server ready message)
|
|
129
|
-
setTimeout(() => openBrowser(LOCAL_URL), BROWSER_DELAY);
|
|
130
|
-
|
|
131
|
-
} catch (error) {
|
|
132
|
-
console.error('❌ Error:', error.message);
|
|
133
|
-
process.exit(1);
|
|
78
|
+
await fs.access(bundleLockPath)
|
|
79
|
+
} catch {
|
|
80
|
+
console.log('\n2️⃣ Installing Jekyll dependencies...')
|
|
81
|
+
await runCommand('bundle', ['install'], {
|
|
82
|
+
cwd: path.join(projectRoot, 'docs')
|
|
83
|
+
})
|
|
134
84
|
}
|
|
85
|
+
|
|
86
|
+
// Step 3: Start Jekyll server in background
|
|
87
|
+
console.log('\n3️⃣ Starting Jekyll server...')
|
|
88
|
+
const jekyll = spawn('bundle', ['exec', 'jekyll', 'serve', '--watch'], {
|
|
89
|
+
cwd: path.join(projectRoot, 'docs'),
|
|
90
|
+
stdio: 'pipe',
|
|
91
|
+
shell: true
|
|
92
|
+
})
|
|
93
|
+
|
|
94
|
+
// Handle server output
|
|
95
|
+
jekyll.stdout.on('data', (data) => {
|
|
96
|
+
const output = data.toString()
|
|
97
|
+
process.stdout.write(output)
|
|
98
|
+
|
|
99
|
+
// Open browser when server is ready
|
|
100
|
+
if (output.includes('Server running') || output.includes('Server address:')) {
|
|
101
|
+
setTimeout(() => openBrowser(LOCAL_URL), 1000)
|
|
102
|
+
}
|
|
103
|
+
})
|
|
104
|
+
|
|
105
|
+
jekyll.stderr.on('data', (data) => {
|
|
106
|
+
process.stderr.write(data)
|
|
107
|
+
})
|
|
108
|
+
|
|
109
|
+
// Handle shutdown
|
|
110
|
+
process.on('SIGINT', () => {
|
|
111
|
+
console.log('\n\n👋 Shutting down Jekyll server...')
|
|
112
|
+
jekyll.kill()
|
|
113
|
+
process.exit(0)
|
|
114
|
+
})
|
|
115
|
+
|
|
116
|
+
jekyll.on('error', (err) => {
|
|
117
|
+
console.error('❌ Jekyll server error:', err)
|
|
118
|
+
process.exit(1)
|
|
119
|
+
})
|
|
120
|
+
|
|
121
|
+
jekyll.on('exit', (code) => {
|
|
122
|
+
if (code !== 0 && code !== null) {
|
|
123
|
+
console.error(`❌ Jekyll server exited with code ${code}`)
|
|
124
|
+
process.exit(code)
|
|
125
|
+
}
|
|
126
|
+
})
|
|
127
|
+
|
|
128
|
+
// Wait a bit then try to open browser anyway (in case we missed the server ready message)
|
|
129
|
+
setTimeout(() => openBrowser(LOCAL_URL), BROWSER_DELAY)
|
|
130
|
+
} catch (error) {
|
|
131
|
+
console.error('❌ Error:', error.message)
|
|
132
|
+
process.exit(1)
|
|
133
|
+
}
|
|
135
134
|
}
|
|
136
135
|
|
|
137
136
|
// Run the script
|
|
138
|
-
main()
|
|
137
|
+
main()
|
package/test-debug.js
CHANGED
|
@@ -1,29 +1,29 @@
|
|
|
1
|
-
import { createBasicApi } from './tests/fixtures/api-configs.js'
|
|
2
|
-
import { cleanTables, createJsonApiDocument, createRelationship } from './tests/helpers/test-utils.js'
|
|
3
|
-
import knex from 'knex'
|
|
1
|
+
import { createBasicApi } from './tests/fixtures/api-configs.js'
|
|
2
|
+
import { cleanTables, createJsonApiDocument, createRelationship } from './tests/helpers/test-utils.js'
|
|
3
|
+
import knex from 'knex'
|
|
4
4
|
|
|
5
5
|
const dbConfig = {
|
|
6
6
|
client: 'better-sqlite3',
|
|
7
7
|
connection: { filename: ':memory:' },
|
|
8
8
|
useNullAsDefault: true
|
|
9
|
-
}
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
const db = knex(dbConfig)
|
|
10
12
|
|
|
11
|
-
|
|
13
|
+
async function test () {
|
|
14
|
+
const api = await createBasicApi(db)
|
|
12
15
|
|
|
13
|
-
async function test() {
|
|
14
|
-
const api = await createBasicApi(db);
|
|
15
|
-
|
|
16
16
|
// Create test data
|
|
17
|
-
await cleanTables(db, ['basic_countries', 'basic_publishers', 'basic_authors', 'basic_books', 'basic_book_authors'])
|
|
18
|
-
|
|
17
|
+
await cleanTables(db, ['basic_countries', 'basic_publishers', 'basic_authors', 'basic_books', 'basic_book_authors'])
|
|
18
|
+
|
|
19
19
|
// Create a country first
|
|
20
|
-
const countryDoc = createJsonApiDocument('countries', { name: 'Test Country', code: 'TC' })
|
|
21
|
-
const country = await api.resources.countries.post({ inputRecord: countryDoc })
|
|
22
|
-
|
|
20
|
+
const countryDoc = createJsonApiDocument('countries', { name: 'Test Country', code: 'TC' })
|
|
21
|
+
const country = await api.resources.countries.post({ inputRecord: countryDoc })
|
|
22
|
+
|
|
23
23
|
// Create an author
|
|
24
|
-
const authorDoc = createJsonApiDocument('authors', { name: 'Test Author' })
|
|
25
|
-
const author = await api.resources.authors.post({ inputRecord: authorDoc })
|
|
26
|
-
|
|
24
|
+
const authorDoc = createJsonApiDocument('authors', { name: 'Test Author' })
|
|
25
|
+
const author = await api.resources.authors.post({ inputRecord: authorDoc })
|
|
26
|
+
|
|
27
27
|
// Create a book with proper relationships
|
|
28
28
|
const bookDoc = {
|
|
29
29
|
data: {
|
|
@@ -33,27 +33,27 @@ async function test() {
|
|
|
33
33
|
country: { data: { type: 'countries', id: String(country.data.id) } }
|
|
34
34
|
}
|
|
35
35
|
}
|
|
36
|
-
}
|
|
37
|
-
const book = await api.resources.books.post({ inputRecord: bookDoc })
|
|
38
|
-
|
|
36
|
+
}
|
|
37
|
+
const book = await api.resources.books.post({ inputRecord: bookDoc })
|
|
38
|
+
|
|
39
39
|
// Create the many-to-many relationship
|
|
40
40
|
await db('basic_book_authors').insert({
|
|
41
41
|
author_id: author.data.id,
|
|
42
42
|
book_id: book.data.id
|
|
43
|
-
})
|
|
44
|
-
|
|
43
|
+
})
|
|
44
|
+
|
|
45
45
|
// Now try to query authors with books included
|
|
46
|
-
console.log('Querying authors with books included...')
|
|
46
|
+
console.log('Querying authors with books included...')
|
|
47
47
|
try {
|
|
48
48
|
const result = await api.resources.authors.query({
|
|
49
49
|
queryParams: { include: ['books'] }
|
|
50
|
-
})
|
|
51
|
-
console.log('Success!', JSON.stringify(result, null, 2))
|
|
50
|
+
})
|
|
51
|
+
console.log('Success!', JSON.stringify(result, null, 2))
|
|
52
52
|
} catch (error) {
|
|
53
|
-
console.error('Error:', error.message)
|
|
53
|
+
console.error('Error:', error.message)
|
|
54
54
|
}
|
|
55
|
-
|
|
56
|
-
await db.destroy()
|
|
55
|
+
|
|
56
|
+
await db.destroy()
|
|
57
57
|
}
|
|
58
58
|
|
|
59
|
-
test().catch(console.error)
|
|
59
|
+
test().catch(console.error)
|