@kollors/deep-json-server 1.0.0-rc.3 → 1.0.0-rc.4
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/CHANGELOG.md +7 -0
- package/MIGRATION.md +2 -2
- package/README.md +8 -3
- package/README.ru.md +8 -3
- package/dist/src/core/constants.d.ts +1 -1
- package/dist/src/core/constants.js +1 -1
- package/dist/src/core/query/compare.d.ts +2 -0
- package/dist/src/core/query/compare.js +8 -0
- package/dist/src/core/query/compare.js.map +1 -0
- package/dist/src/core/query/execute.js +2 -10
- package/dist/src/core/query/execute.js.map +1 -1
- package/dist/src/core/query/filter.js +5 -4
- package/dist/src/core/query/filter.js.map +1 -1
- package/dist/src/files/disk-paths.js +1 -1
- package/dist/src/files/disk-paths.js.map +1 -1
- package/dist/src/server/bootstrap.js +51 -41
- package/dist/src/server/bootstrap.js.map +1 -1
- package/dist/src/server/input-paths.js +4 -1
- package/dist/src/server/input-paths.js.map +1 -1
- package/dist/src/server/storage-lock.d.ts +3 -0
- package/dist/src/server/storage-lock.js +116 -0
- package/dist/src/server/storage-lock.js.map +1 -0
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,12 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 1.0.0-rc.4
|
|
4
|
+
|
|
5
|
+
- Prevent concurrent servers from writing to the same file-backed database and recover its lock after a process crash, using built-in Node.js APIs.
|
|
6
|
+
- Make range filters and sorting use the same comparison rules across REST and GraphQL.
|
|
7
|
+
- Execute key examples from both READMEs during tests to keep the documented behavior current.
|
|
8
|
+
- Add a database benchmark script for memory and file storage; runtime query behavior is unchanged by the benchmark.
|
|
9
|
+
|
|
3
10
|
## 1.0.0-rc.3
|
|
4
11
|
|
|
5
12
|
- Keep relation keys inferred from `source` in stored records while hiding them from REST, GraphQL, and OpenAPI unless declared explicitly in model `fields`.
|
package/MIGRATION.md
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
# Migrating from 0.9.0 to 1.0.0-rc.
|
|
1
|
+
# Migrating from 0.9.0 to 1.0.0-rc.4
|
|
2
2
|
|
|
3
3
|
Version 1.0 changes configuration and request syntax. Update the server configuration and client requests together. Back up any file database, auth records, and file metadata before changing the running server.
|
|
4
4
|
|
|
@@ -6,7 +6,7 @@ Version 1.0 changes configuration and request syntax. Update the server configur
|
|
|
6
6
|
|
|
7
7
|
Declare a storage mode and use `source` for each enabled component:
|
|
8
8
|
|
|
9
|
-
| 0.9.0 | 1.0.0-rc.
|
|
9
|
+
| 0.9.0 | 1.0.0-rc.4 |
|
|
10
10
|
|---|---|
|
|
11
11
|
| `database.path` | `storage: 'file'`, `database.source` |
|
|
12
12
|
| `database.data` | `storage: 'memory'`, `database.source` |
|
package/README.md
CHANGED
|
@@ -14,7 +14,7 @@ A JSON mock server with REST, GraphQL, related records, file uploads and schema
|
|
|
14
14
|
npm install @kollors/deep-json-server@rc
|
|
15
15
|
```
|
|
16
16
|
|
|
17
|
-
To install this release candidate, use `@1.0.0-rc.
|
|
17
|
+
To install this release candidate, use `@1.0.0-rc.4`.
|
|
18
18
|
|
|
19
19
|
## Quick start
|
|
20
20
|
|
|
@@ -100,6 +100,7 @@ export default {
|
|
|
100
100
|
|
|
101
101
|
Set the root `api` in `schema.json`:
|
|
102
102
|
|
|
103
|
+
<!-- tested-example: graphql-only-schema -->
|
|
103
104
|
```json
|
|
104
105
|
{
|
|
105
106
|
"api": ["graphql"],
|
|
@@ -131,6 +132,7 @@ Address precedence: CLI → configuration → `HOST`/`PORT` → defaults. Withou
|
|
|
131
132
|
|
|
132
133
|
Examples: [database](examples/database.json), [model schema](examples/schema.json), [configuration](examples/server.config.js).
|
|
133
134
|
|
|
135
|
+
<!-- tested-example: implicit-relation-schema -->
|
|
134
136
|
```json
|
|
135
137
|
{
|
|
136
138
|
"api": ["rest", "graphql"],
|
|
@@ -372,7 +374,7 @@ Primitive arrays are returned as plain arrays. Every object list accepts optiona
|
|
|
372
374
|
|
|
373
375
|
Use `page` and `pageSize` in `pager`. The default is the first page with the size from `server.pageSize`. Both values must be positive integers; `pageSize` is limited by `server.maxPageSize`. Out-of-range pages return empty `data` with the total matching record count in `total`.
|
|
374
376
|
|
|
375
|
-
`where` uses field operators `eq`, `ne`, `in`, string `contains`/`startsWith`/`endsWith`, and comparisons `gt`, `gte`, `lt`, `lte`. Conditions in the same object must all match. `and` and `or` take arrays of conditions; `not` takes one condition and can also be used inside a field filter. Arrays support `some`, `every`, `none`; primitive arrays also support `contains`, `in`. String `contains`, `startsWith` and `endsWith` ignore case; `eq`, `ne` and `in` compare exact values. A field condition is an object containing an operator, such as `{ "id": { "eq": "1" } }`.
|
|
377
|
+
`where` uses field operators `eq`, `ne`, `in`, string `contains`/`startsWith`/`endsWith`, and comparisons `gt`, `gte`, `lt`, `lte`. Conditions in the same object must all match. `and` and `or` take arrays of conditions; `not` takes one condition and can also be used inside a field filter. Arrays support `some`, `every`, `none`; primitive arrays also support `contains`, `in`. String `contains`, `startsWith` and `endsWith` ignore case; `eq`, `ne` and `in` compare exact values. For strings, `gt`, `gte`, `lt` and `lte` use the same case-insensitive, numeric-aware order as sorting. A field condition is an object containing an operator, such as `{ "id": { "eq": "1" } }`.
|
|
376
378
|
|
|
377
379
|
```json
|
|
378
380
|
{
|
|
@@ -415,6 +417,7 @@ REST record routes accept one query parameter, `scope`, containing a JSON array
|
|
|
415
417
|
|
|
416
418
|
Select users and their movies with independent ordering and pagination:
|
|
417
419
|
|
|
420
|
+
<!-- tested-example: rest-user-list -->
|
|
418
421
|
```js
|
|
419
422
|
const scope = [
|
|
420
423
|
{
|
|
@@ -439,6 +442,7 @@ Select scalars and primitive arrays with `true`, and objects or relations with t
|
|
|
439
442
|
|
|
440
443
|
For example, select a movie's own fields, its actors' users and sorted genres:
|
|
441
444
|
|
|
445
|
+
<!-- tested-example: rest-movie-scope -->
|
|
442
446
|
```json
|
|
443
447
|
[
|
|
444
448
|
{
|
|
@@ -530,6 +534,7 @@ npx deep-json-server server.config.js
|
|
|
530
534
|
|
|
531
535
|
Send requests to `/graphql` using POST with `Content-Type: application/json` and a body of `{ "query": "…", "variables": {} }`. Change the path through `graphql.endpoint`.
|
|
532
536
|
|
|
537
|
+
<!-- tested-example: graphql-user-list -->
|
|
533
538
|
```graphql
|
|
534
539
|
query {
|
|
535
540
|
userList(
|
|
@@ -827,7 +832,7 @@ Content-Type: application/json
|
|
|
827
832
|
|
|
828
833
|
In disk mode, the binary is stored at `<files.source>/<directory>/<name>`. Metadata defaults to `<files.source>/.files.json`; set `files.metadata` for another location. Directories and the metadata file are created when needed.
|
|
829
834
|
|
|
830
|
-
Use one server process per disk database and file store. Stop
|
|
835
|
+
Use one server process per disk database and file store. A second server using the same database file fails at startup; closing the first server releases its lock, and a lock left by a crashed process is recovered on the next start. Stop the server before editing stored files or metadata manually. Storage paths cannot contain symbolic links. Uploads and renames cannot overwrite the database, its lock, counters, schema, auth users, loaded configuration or metadata file.
|
|
831
836
|
|
|
832
837
|
Send the file as a binary request body. In a browser, use `xhr.send(file)` and track progress through `XMLHttpRequest.upload.onprogress`. The default maximum size is 100 MiB and can be changed through `server.maxFileSize`. Missing or unsafe headers and paths return `400`, an exceeded limit returns `413`, and a missing, malformed, or Fastify-unsupported `Content-Type` returns `400` or `415`, depending on which validation stage rejects it.
|
|
833
838
|
|
package/README.ru.md
CHANGED
|
@@ -14,7 +14,7 @@ JSON-сервер для создания тестового API с REST, GraphQ
|
|
|
14
14
|
npm install @kollors/deep-json-server@rc
|
|
15
15
|
```
|
|
16
16
|
|
|
17
|
-
Для установки этого релиз-кандидата укажите `@1.0.0-rc.
|
|
17
|
+
Для установки этого релиз-кандидата укажите `@1.0.0-rc.4`.
|
|
18
18
|
|
|
19
19
|
## Быстрый старт
|
|
20
20
|
|
|
@@ -100,6 +100,7 @@ export default {
|
|
|
100
100
|
|
|
101
101
|
В корне `schema.json` задайте `api`:
|
|
102
102
|
|
|
103
|
+
<!-- tested-example: graphql-only-schema -->
|
|
103
104
|
```json
|
|
104
105
|
{
|
|
105
106
|
"api": ["graphql"],
|
|
@@ -131,6 +132,7 @@ export default {
|
|
|
131
132
|
|
|
132
133
|
Примеры: [база данных](examples/database.json), [схема моделей](examples/schema.json), [конфигурация](examples/server.config.js).
|
|
133
134
|
|
|
135
|
+
<!-- tested-example: implicit-relation-schema -->
|
|
134
136
|
```json
|
|
135
137
|
{
|
|
136
138
|
"api": ["rest", "graphql"],
|
|
@@ -372,7 +374,7 @@ npx deep-json-server examples/server.config.js
|
|
|
372
374
|
|
|
373
375
|
В `pager` задаются `page` и `pageSize`. По умолчанию возвращается первая страница с размером из `server.pageSize`. Оба значения должны быть положительными целыми числами; `pageSize` ограничен `server.maxPageSize`. За пределами списка возвращается пустой `data` с общим числом найденных записей в `total`.
|
|
374
376
|
|
|
375
|
-
Фильтры: `eq`, `ne`, `in`; для строк `contains`, `startsWith`, `endsWith`; сравнения `gt`, `gte`, `lt`, `lte`. Несколько условий в одном объекте должны выполняться одновременно. `and` и `or` принимают массив условий, `not` — одно условие; `not` также можно использовать внутри фильтра поля. У массивов есть `some`, `every`, `none`; у примитивных массивов также `contains`, `in`. `contains`, `startsWith` и `endsWith` для строк не учитывают регистр; `eq`, `ne` и `in` сравнивают точные значения. Условие поля задаётся объектом с оператором, например `{ "id": { "eq": "1" } }`.
|
|
377
|
+
Фильтры: `eq`, `ne`, `in`; для строк `contains`, `startsWith`, `endsWith`; сравнения `gt`, `gte`, `lt`, `lte`. Несколько условий в одном объекте должны выполняться одновременно. `and` и `or` принимают массив условий, `not` — одно условие; `not` также можно использовать внутри фильтра поля. У массивов есть `some`, `every`, `none`; у примитивных массивов также `contains`, `in`. `contains`, `startsWith` и `endsWith` для строк не учитывают регистр; `eq`, `ne` и `in` сравнивают точные значения. Для строк `gt`, `gte`, `lt` и `lte` используют тот же порядок, что сортировка: без учёта регистра и с числовым сравнением фрагментов строки. Условие поля задаётся объектом с оператором, например `{ "id": { "eq": "1" } }`.
|
|
376
378
|
|
|
377
379
|
```json
|
|
378
380
|
{
|
|
@@ -415,6 +417,7 @@ POST возвращает созданную запись со статусом
|
|
|
415
417
|
|
|
416
418
|
Пример выбора пользователей и их фильмов с отдельной сортировкой и пагинацией:
|
|
417
419
|
|
|
420
|
+
<!-- tested-example: rest-user-list -->
|
|
418
421
|
```js
|
|
419
422
|
const scope = [
|
|
420
423
|
{
|
|
@@ -439,6 +442,7 @@ const response = await fetch(`/users?${params}`);
|
|
|
439
442
|
|
|
440
443
|
Например, собственные поля фильма, пользователи актёров и отсортированные жанры:
|
|
441
444
|
|
|
445
|
+
<!-- tested-example: rest-movie-scope -->
|
|
442
446
|
```json
|
|
443
447
|
[
|
|
444
448
|
{
|
|
@@ -530,6 +534,7 @@ npx deep-json-server server.config.js
|
|
|
530
534
|
|
|
531
535
|
Отправляйте запросы на `/graphql` методом POST с `Content-Type: application/json` и телом `{ "query": "…", "variables": {} }`. Путь можно изменить через `graphql.endpoint`.
|
|
532
536
|
|
|
537
|
+
<!-- tested-example: graphql-user-list -->
|
|
533
538
|
```graphql
|
|
534
539
|
query {
|
|
535
540
|
userList(
|
|
@@ -827,7 +832,7 @@ Content-Type: application/json
|
|
|
827
832
|
|
|
828
833
|
При хранении на диске бинарный файл находится по пути `<files.source>/<directory>/<name>`. Метаданные по умолчанию хранятся в `<files.source>/.files.json`; другой путь можно задать через `files.metadata`. Директории и файл метаданных создаются по мере необходимости.
|
|
829
834
|
|
|
830
|
-
Используйте один процесс сервера для дисковой базы и файлового хранилища. Перед ручным изменением файлов или метаданных остановите
|
|
835
|
+
Используйте один процесс сервера для дисковой базы и файлового хранилища. Второй сервер с тем же файлом базы не запустится; закрытие первого освобождает блокировку, а после аварийного завершения она снимается при следующем запуске. Перед ручным изменением файлов или метаданных остановите сервер. Пути в хранилище не могут содержать символические ссылки. Загрузка и переименование не могут перезаписать базу, её блокировку, счётчики, схему, учётные записи auth, загруженную конфигурацию или файл метаданных.
|
|
831
836
|
|
|
832
837
|
Отправляйте файл как бинарное тело запроса. В браузере для этого можно использовать `xhr.send(file)`, а прогресс отслеживать через `XMLHttpRequest.upload.onprogress`. Максимальный размер по умолчанию равен 100 МиБ и настраивается через `server.maxFileSize`. Отсутствующие или небезопасные заголовки и пути возвращают `400`, превышение лимита — `413`, а отсутствующий, некорректный или не поддерживаемый Fastify `Content-Type` — `400` либо `415` в зависимости от этапа проверки.
|
|
833
838
|
|
|
@@ -3,4 +3,4 @@ export declare const DEFAULT_MAX_FILE_SIZE: number;
|
|
|
3
3
|
export declare const DEFAULT_MAX_PAGE_SIZE = 100;
|
|
4
4
|
export declare const DEFAULT_PAGE_SIZE = 10;
|
|
5
5
|
export declare const DEFAULT_PORT = 4001;
|
|
6
|
-
export declare const VERSION = "1.0.0-rc.
|
|
6
|
+
export declare const VERSION = "1.0.0-rc.4";
|
|
@@ -3,5 +3,5 @@ export const DEFAULT_MAX_FILE_SIZE = 100 * 1024 * 1024;
|
|
|
3
3
|
export const DEFAULT_MAX_PAGE_SIZE = 100;
|
|
4
4
|
export const DEFAULT_PAGE_SIZE = 10;
|
|
5
5
|
export const DEFAULT_PORT = 4001;
|
|
6
|
-
export const VERSION = '1.0.0-rc.
|
|
6
|
+
export const VERSION = '1.0.0-rc.4';
|
|
7
7
|
//# sourceMappingURL=constants.js.map
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
const collator = new Intl.Collator('en', { numeric: true, sensitivity: 'base' });
|
|
2
|
+
/** Задаёт один порядок строк и чисел для фильтров и сортировки. */
|
|
3
|
+
export function compareValues(left, right) {
|
|
4
|
+
if (typeof left === 'number' && typeof right === 'number')
|
|
5
|
+
return left - right;
|
|
6
|
+
return collator.compare(String(left), String(right));
|
|
7
|
+
}
|
|
8
|
+
//# sourceMappingURL=compare.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"compare.js","sourceRoot":"","sources":["../../../../src/core/query/compare.ts"],"names":[],"mappings":"AAAA,MAAM,QAAQ,GAAG,IAAI,IAAI,CAAC,QAAQ,CAAC,IAAI,EAAE,EAAE,OAAO,EAAE,IAAI,EAAE,WAAW,EAAE,MAAM,EAAE,CAAC,CAAC;AAEjF,mEAAmE;AACnE,MAAM,UAAU,aAAa,CAAC,IAAqB,EAAE,KAAsB;IACzE,IAAI,OAAO,IAAI,KAAK,QAAQ,IAAI,OAAO,KAAK,KAAK,QAAQ;QAAE,OAAO,IAAI,GAAG,KAAK,CAAC;IAC/E,OAAO,QAAQ,CAAC,OAAO,CAAC,MAAM,CAAC,IAAI,CAAC,EAAE,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC;AACvD,CAAC"}
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { readPath } from '../model/tree.js';
|
|
2
2
|
import { isRef, resolveField } from '../records.js';
|
|
3
3
|
import { hasOnlyKeys, isObject } from '../utils.js';
|
|
4
|
+
import { compareValues } from './compare.js';
|
|
4
5
|
import { compileWhere } from './filter.js';
|
|
5
6
|
import { badQuery, nodeAt } from './options.js';
|
|
6
7
|
/** Создаёт представление записи для фильтра, скрывая поля только для записи.
|
|
@@ -19,7 +20,6 @@ function filterView(ref) {
|
|
|
19
20
|
});
|
|
20
21
|
return value;
|
|
21
22
|
}
|
|
22
|
-
const collator = new Intl.Collator('en', { numeric: true, sensitivity: 'base' });
|
|
23
23
|
/** Проверяет аргументы списка и превращает их в готовый план выполнения.
|
|
24
24
|
* @example { pager: { page: 2, pageSize: 5 } } → план с page: 2 и pageSize: 5.
|
|
25
25
|
*/
|
|
@@ -63,15 +63,7 @@ export function executeList(records, prepared) {
|
|
|
63
63
|
for (const [index, rule] of rules.entries()) {
|
|
64
64
|
const left = leftEntry.keys[index];
|
|
65
65
|
const right = rightEntry.keys[index];
|
|
66
|
-
const comparison = left == null && right == null
|
|
67
|
-
? 0
|
|
68
|
-
: left == null
|
|
69
|
-
? 1
|
|
70
|
-
: right == null
|
|
71
|
-
? -1
|
|
72
|
-
: typeof left === 'number' && typeof right === 'number'
|
|
73
|
-
? left - right
|
|
74
|
-
: collator.compare(String(left), String(right));
|
|
66
|
+
const comparison = left == null && right == null ? 0 : left == null ? 1 : right == null ? -1 : compareValues(left, right);
|
|
75
67
|
if (comparison)
|
|
76
68
|
return rule.direction === 'DESC' ? -comparison : comparison;
|
|
77
69
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"execute.js","sourceRoot":"","sources":["../../../../src/core/query/execute.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,kBAAkB,CAAC;AAE5C,OAAO,EAAE,KAAK,EAAY,YAAY,EAAE,MAAM,eAAe,CAAC;AAC9D,OAAO,EAAE,WAAW,EAAE,QAAQ,EAAE,MAAM,aAAa,CAAC;AACpD,OAAO,EAAE,YAAY,EAAkB,MAAM,aAAa,CAAC;AAC3D,OAAO,EAAE,QAAQ,EAAoB,MAAM,EAAE,MAAM,cAAc,CAAC;AAclE;;GAEG;AACH,SAAS,UAAU,CAAC,GAAQ;IAC1B,MAAM,KAAK,GAA4B,EAAE,CAAC;IAC1C,KAAK,MAAM,CAAC,IAAI,EAAE,IAAI,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC,QAAQ,CAAC;QAC1D,IAAI,CAAC,IAAI,CAAC,SAAS,IAAI,CAAC,IAAI,CAAC,OAAO;YAClC,MAAM,CAAC,cAAc,CAAC,KAAK,EAAE,IAAI,EAAE;gBACjC,UAAU,EAAE,IAAI;gBAChB,GAAG,EAAE,GAAG,EAAE;oBACR,MAAM,KAAK,GAAG,YAAY,CAAC,GAAG,EAAE,IAAI,EAAE,IAAI,CAAC,CAAC;oBAC5C,OAAO,KAAK,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,UAAU,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,UAAU,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC;gBACxI,CAAC;aACF,CAAC,CAAC;IACP,OAAO,KAAK,CAAC;AACf,CAAC;AAED
|
|
1
|
+
{"version":3,"file":"execute.js","sourceRoot":"","sources":["../../../../src/core/query/execute.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { mentionsDeletedAt } from '../lifecycle/options.js';
|
|
2
2
|
import { isEqual, isObject } from '../utils.js';
|
|
3
|
+
import { compareValues } from './compare.js';
|
|
3
4
|
import { operatorsFor } from './contract.js';
|
|
4
5
|
import { badQuery, childrenOf } from './options.js';
|
|
5
6
|
const comparable = (value) => typeof value === 'string' || typeof value === 'number';
|
|
@@ -56,13 +57,13 @@ function condition(node, input, depth) {
|
|
|
56
57
|
case 'endsWith':
|
|
57
58
|
return (field) => typeof field === 'string' && field.toLowerCase().endsWith(String(value).toLowerCase());
|
|
58
59
|
case 'gt':
|
|
59
|
-
return (field) => comparable(field) && comparable(value) && field >
|
|
60
|
+
return (field) => comparable(field) && comparable(value) && compareValues(field, value) > 0;
|
|
60
61
|
case 'gte':
|
|
61
|
-
return (field) => comparable(field) && comparable(value) && field >=
|
|
62
|
+
return (field) => comparable(field) && comparable(value) && compareValues(field, value) >= 0;
|
|
62
63
|
case 'lt':
|
|
63
|
-
return (field) => comparable(field) && comparable(value) && field <
|
|
64
|
+
return (field) => comparable(field) && comparable(value) && compareValues(field, value) < 0;
|
|
64
65
|
default:
|
|
65
|
-
return (field) => comparable(field) && comparable(value) && field <=
|
|
66
|
+
return (field) => comparable(field) && comparable(value) && compareValues(field, value) <= 0;
|
|
66
67
|
}
|
|
67
68
|
});
|
|
68
69
|
return (value) => predicates.every((predicate) => predicate(value));
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"filter.js","sourceRoot":"","sources":["../../../../src/core/query/filter.ts"],"names":[],"mappings":"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
|
|
1
|
+
{"version":3,"file":"filter.js","sourceRoot":"","sources":["../../../../src/core/query/filter.ts"],"names":[],"mappings":"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"}
|
|
@@ -33,7 +33,7 @@ export async function createDiskPaths({ directory, metadata, staging, protectedP
|
|
|
33
33
|
const resolveFilePath = (path) => {
|
|
34
34
|
const filePath = resolve(directory, path);
|
|
35
35
|
const canonical = resolve(realDirectory, relative(directory, filePath));
|
|
36
|
-
if (protectedPaths.
|
|
36
|
+
if ([...protectedPaths].some((protectedPath) => isPathInside(protectedPath, canonical)))
|
|
37
37
|
throw domainError('INVALID_INPUT', 'Path is reserved for a server input file');
|
|
38
38
|
if (filePath === directory || !isPathInside(directory, filePath) || filePath === metadata || isPathInside(staging, filePath))
|
|
39
39
|
throw domainError('INVALID_INPUT', 'File path escapes the storage directory');
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"disk-paths.js","sourceRoot":"","sources":["../../../src/files/disk-paths.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,KAAK,EAAE,KAAK,EAAE,QAAQ,EAAE,MAAM,kBAAkB,CAAC;AAClE,OAAO,EAAE,OAAO,EAAE,UAAU,EAAE,QAAQ,EAAE,OAAO,EAAE,GAAG,EAAE,MAAM,WAAW,CAAC;AACxE,OAAO,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAChD,OAAO,EAAE,aAAa,EAAE,MAAM,kBAAkB,CAAC;AAEjD,MAAM,UAAU,GAAG,KAAK,EAAE,IAAY,EAAoB,EAAE;IAC1D,IAAI,CAAC;QACH,MAAM,MAAM,CAAC,IAAI,CAAC,CAAC;QACnB,OAAO,IAAI,CAAC;IACd,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,IAAI,aAAa,CAAC,KAAK,CAAC,IAAI,KAAK,CAAC,IAAI,KAAK,QAAQ;YAAE,OAAO,KAAK,CAAC;QAClE,MAAM,KAAK,CAAC;IACd,CAAC;AACH,CAAC,CAAC;AAEF,MAAM,YAAY,GAAG,CAAC,QAAgB,EAAE,UAAkB,EAAW,EAAE;IACrE,MAAM,YAAY,GAAG,QAAQ,CAAC,QAAQ,EAAE,UAAU,CAAC,CAAC;IACpD,OAAO,YAAY,KAAK,EAAE,IAAI,CAAC,YAAY,KAAK,IAAI,IAAI,CAAC,YAAY,CAAC,UAAU,CAAC,KAAK,GAAG,EAAE,CAAC,IAAI,CAAC,UAAU,CAAC,YAAY,CAAC,CAAC,CAAC;AAC7H,CAAC,CAAC;AAEF,MAAM,iBAAiB,GAAG,CAAC,KAA4B,EAAQ,EAAE;IAC/D,IAAI,CAAC,KAAK,CAAC,MAAM,EAAE;QAAE,MAAM,WAAW,CAAC,eAAe,EAAE,mCAAmC,CAAC,CAAC;AAC/F,CAAC,CAAC;AAEF;;GAEG;AACH,MAAM,CAAC,KAAK,UAAU,eAAe,CAAC,EAAE,SAAS,EAAE,QAAQ,EAAE,OAAO,EAAE,cAAc,EAAyF;IAC3K,MAAM,aAAa,GAAG,MAAM,QAAQ,CAAC,SAAS,CAAC,CAAC;IAChD,MAAM,eAAe,GAAG,CAAC,IAAY,EAAQ,EAAE;QAC7C,IAAI,CAAC,YAAY,CAAC,aAAa,EAAE,IAAI,CAAC;YAAE,MAAM,WAAW,CAAC,eAAe,EAAE,yCAAyC,CAAC,CAAC;IACxH,CAAC,CAAC;IACF,MAAM,eAAe,GAAG,CAAC,IAAY,EAAU,EAAE;QAC/C,MAAM,QAAQ,GAAG,OAAO,CAAC,SAAS,EAAE,IAAI,CAAC,CAAC;QAC1C,MAAM,SAAS,GAAG,OAAO,CAAC,aAAa,EAAE,QAAQ,CAAC,SAAS,EAAE,QAAQ,CAAC,CAAC,CAAC;QACxE,IAAI,cAAc,CAAC,
|
|
1
|
+
{"version":3,"file":"disk-paths.js","sourceRoot":"","sources":["../../../src/files/disk-paths.ts"],"names":[],"mappings":"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"}
|
|
@@ -2,52 +2,62 @@ import { AUTH_PATHS } from '../auth/contract.js';
|
|
|
2
2
|
import { configSourcePath } from './config.js';
|
|
3
3
|
import { validateEndpoints } from './features.js';
|
|
4
4
|
import { inputPaths } from './input-paths.js';
|
|
5
|
+
import { acquireDatabaseLock } from './storage-lock.js';
|
|
5
6
|
/** Подключает к HTTP-серверу хранилище записей и включённые прикладные модули.
|
|
6
7
|
* @example Конфигурация только с базой → REST-маршруты без auth, files и API-экспортов.
|
|
7
8
|
*/
|
|
8
9
|
export async function registerConfiguredModules(app, config, explicitModel, openapi) {
|
|
9
|
-
const
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
10
|
+
const release = typeof config.database.source === 'string' ? await acquireDatabaseLock(config.database.source) : undefined;
|
|
11
|
+
try {
|
|
12
|
+
const enabled = { auth: config.auth !== undefined, files: config.files !== undefined };
|
|
13
|
+
const recordSettings = { auth: enabled.auth };
|
|
14
|
+
const keys = explicitModel ? new Map(explicitModel.entities.map((entity) => [entity.collection, entity.primary])) : undefined;
|
|
15
|
+
const [{ createDatabaseStore }, { Engine }, { inferModel }, { registerRestRoutes }] = await Promise.all([
|
|
16
|
+
import('../core/database.js'),
|
|
17
|
+
import('../core/engine.js'),
|
|
18
|
+
import('../core/model.js'),
|
|
19
|
+
import('../rest/routes.js'),
|
|
20
|
+
]);
|
|
21
|
+
const store = await createDatabaseStore(config.database, keys);
|
|
22
|
+
const model = explicitModel ?? inferModel(store.database.data, recordSettings);
|
|
23
|
+
const engine = new Engine(store, model, config.server.pageSize, config.server.maxPageSize);
|
|
24
|
+
engine.validateData(store.database.data);
|
|
25
|
+
const graphqlPath = config.graphql?.endpoint;
|
|
26
|
+
const openapiPath = config.openapi?.endpoint;
|
|
27
|
+
validateEndpoints(model.api.includes('rest') ? model.entities.filter((entity) => entity.api.includes('rest')).map((entity) => entity.collection) : [], [
|
|
28
|
+
...(graphqlPath ? [graphqlPath] : []),
|
|
29
|
+
...(openapiPath ? [openapiPath] : []),
|
|
30
|
+
...(enabled.auth ? Object.values(AUTH_PATHS) : []),
|
|
31
|
+
]);
|
|
32
|
+
const auth = enabled.auth && config.auth ? await (await import('../auth/service.js')).createAuthService(config.auth) : undefined;
|
|
33
|
+
if (auth) {
|
|
34
|
+
app.addHook('onClose', async () => auth.close());
|
|
35
|
+
const { registerAuthRoutes } = await import('../auth/routes.js');
|
|
36
|
+
registerAuthRoutes(app, auth);
|
|
37
|
+
}
|
|
38
|
+
const authenticate = auth ? (header) => auth.me(header) : undefined;
|
|
39
|
+
if (model.api.includes('rest'))
|
|
40
|
+
registerRestRoutes(app, engine, authenticate);
|
|
41
|
+
if (graphqlPath) {
|
|
42
|
+
const [{ registerGraphqlRoutes }, { buildGraphql }] = await Promise.all([import('../graphql/routes.js'), import('../graphql/schema.js')]);
|
|
43
|
+
registerGraphqlRoutes(app, buildGraphql(model), engine, graphqlPath, authenticate);
|
|
44
|
+
}
|
|
45
|
+
if (openapiPath) {
|
|
46
|
+
const document = await openapi();
|
|
47
|
+
document.servers = [{ url: '/' }];
|
|
48
|
+
app.get(openapiPath, async () => document);
|
|
49
|
+
}
|
|
50
|
+
if (enabled.files && config.files) {
|
|
51
|
+
const { createFileStore, registerFileRoutes } = await import('../files/index.js');
|
|
52
|
+
const protectedPaths = inputPaths({ database: config.database, auth: config.auth, package: config.package }, '.', configSourcePath(config));
|
|
53
|
+
registerFileRoutes(app, { getStore: () => createFileStore(config.files, protectedPaths), maxFileSize: config.server.maxFileSize });
|
|
54
|
+
}
|
|
55
|
+
if (release)
|
|
56
|
+
app.addHook('onClose', release);
|
|
34
57
|
}
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
if (graphqlPath) {
|
|
39
|
-
const [{ registerGraphqlRoutes }, { buildGraphql }] = await Promise.all([import('../graphql/routes.js'), import('../graphql/schema.js')]);
|
|
40
|
-
registerGraphqlRoutes(app, buildGraphql(model), engine, graphqlPath, authenticate);
|
|
41
|
-
}
|
|
42
|
-
if (openapiPath) {
|
|
43
|
-
const document = await openapi();
|
|
44
|
-
document.servers = [{ url: '/' }];
|
|
45
|
-
app.get(openapiPath, async () => document);
|
|
46
|
-
}
|
|
47
|
-
if (enabled.files && config.files) {
|
|
48
|
-
const { createFileStore, registerFileRoutes } = await import('../files/index.js');
|
|
49
|
-
const protectedPaths = inputPaths({ database: config.database, auth: config.auth, package: config.package }, '.', configSourcePath(config));
|
|
50
|
-
registerFileRoutes(app, { getStore: () => createFileStore(config.files, protectedPaths), maxFileSize: config.server.maxFileSize });
|
|
58
|
+
catch (error) {
|
|
59
|
+
await release?.();
|
|
60
|
+
throw error;
|
|
51
61
|
}
|
|
52
62
|
}
|
|
53
63
|
//# sourceMappingURL=bootstrap.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"bootstrap.js","sourceRoot":"","sources":["../../../src/server/bootstrap.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,UAAU,EAAE,MAAM,qBAAqB,CAAC;AAEjD,OAAO,EAAE,gBAAgB,EAA+B,MAAM,aAAa,CAAC;AAC5E,OAAO,EAAE,iBAAiB,EAAE,MAAM,eAAe,CAAC;AAClD,OAAO,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAC;
|
|
1
|
+
{"version":3,"file":"bootstrap.js","sourceRoot":"","sources":["../../../src/server/bootstrap.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { basename, dirname, resolve } from 'node:path';
|
|
2
2
|
import { isObject } from '../core/utils.js';
|
|
3
|
+
import { databaseLockPath } from './storage-lock.js';
|
|
3
4
|
/** Собирает пути входных файлов, счётчиков и временных файлов записи без чтения диска.
|
|
4
5
|
* @example auth.source = '/tmp/users.json' → среди защищённых путей '/tmp/users.json' и '/tmp/.users.json.tmp'.
|
|
5
6
|
*/
|
|
@@ -16,8 +17,10 @@ export function inputPaths(config, directory = '.', sourcePath) {
|
|
|
16
17
|
auth.source,
|
|
17
18
|
projectPackage.source,
|
|
18
19
|
].filter((path) => typeof path === 'string');
|
|
19
|
-
if (typeof database.source === 'string')
|
|
20
|
+
if (typeof database.source === 'string') {
|
|
20
21
|
paths.push(`${database.source}.counters.json`);
|
|
22
|
+
paths.push(databaseLockPath(database.source), `${databaseLockPath(database.source)}.recovery`);
|
|
23
|
+
}
|
|
21
24
|
// JSONFile использует эти соседние файлы при записи; они тоже содержат защищённые данные.
|
|
22
25
|
for (const path of [database.source, typeof database.source === 'string' ? `${database.source}.counters.json` : undefined, auth.source])
|
|
23
26
|
if (typeof path === 'string')
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"input-paths.js","sourceRoot":"","sources":["../../../src/server/input-paths.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AACvD,OAAO,EAAE,QAAQ,EAAE,MAAM,kBAAkB,CAAC;AAC5C;;GAEG;AACH,MAAM,UAAU,UAAU,CAAC,MAAkF,EAAE,SAAS,GAAG,GAAG,EAAE,UAAmB;IACjJ,MAAM,QAAQ,GAAG,QAAQ,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC,CAAC,EAAE,CAAC;IAClE,MAAM,KAAK,GAAG,QAAQ,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,CAAC;IACzD,MAAM,IAAI,GAAG,QAAQ,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC;IACtD,MAAM,cAAc,GAAG,QAAQ,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,CAAC;IACtE,MAAM,KAAK,GAAG;QACZ,UAAU;QACV,QAAQ,CAAC,MAAM;QACf,QAAQ,CAAC,MAAM;QACf,KAAK,CAAC,QAAQ,IAAI,CAAC,OAAO,KAAK,CAAC,MAAM,KAAK,QAAQ,CAAC,CAAC,CAAC,OAAO,CAAC,SAAS,EAAE,KAAK,CAAC,MAAM,EAAE,aAAa,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC;QAClH,IAAI,CAAC,MAAM;QACX,cAAc,CAAC,MAAM;KACtB,CAAC,MAAM,CAAC,CAAC,IAAI,EAAkB,EAAE,CAAC,OAAO,IAAI,KAAK,QAAQ,CAAC,CAAC;IAC7D,IAAI,OAAO,QAAQ,CAAC,MAAM,KAAK,QAAQ;
|
|
1
|
+
{"version":3,"file":"input-paths.js","sourceRoot":"","sources":["../../../src/server/input-paths.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AACvD,OAAO,EAAE,QAAQ,EAAE,MAAM,kBAAkB,CAAC;AAC5C,OAAO,EAAE,gBAAgB,EAAE,MAAM,mBAAmB,CAAC;AACrD;;GAEG;AACH,MAAM,UAAU,UAAU,CAAC,MAAkF,EAAE,SAAS,GAAG,GAAG,EAAE,UAAmB;IACjJ,MAAM,QAAQ,GAAG,QAAQ,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC,CAAC,EAAE,CAAC;IAClE,MAAM,KAAK,GAAG,QAAQ,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,CAAC;IACzD,MAAM,IAAI,GAAG,QAAQ,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC;IACtD,MAAM,cAAc,GAAG,QAAQ,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,CAAC;IACtE,MAAM,KAAK,GAAG;QACZ,UAAU;QACV,QAAQ,CAAC,MAAM;QACf,QAAQ,CAAC,MAAM;QACf,KAAK,CAAC,QAAQ,IAAI,CAAC,OAAO,KAAK,CAAC,MAAM,KAAK,QAAQ,CAAC,CAAC,CAAC,OAAO,CAAC,SAAS,EAAE,KAAK,CAAC,MAAM,EAAE,aAAa,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC;QAClH,IAAI,CAAC,MAAM;QACX,cAAc,CAAC,MAAM;KACtB,CAAC,MAAM,CAAC,CAAC,IAAI,EAAkB,EAAE,CAAC,OAAO,IAAI,KAAK,QAAQ,CAAC,CAAC;IAC7D,IAAI,OAAO,QAAQ,CAAC,MAAM,KAAK,QAAQ,EAAE,CAAC;QACxC,KAAK,CAAC,IAAI,CAAC,GAAG,QAAQ,CAAC,MAAM,gBAAgB,CAAC,CAAC;QAC/C,KAAK,CAAC,IAAI,CAAC,gBAAgB,CAAC,QAAQ,CAAC,MAAM,CAAC,EAAE,GAAG,gBAAgB,CAAC,QAAQ,CAAC,MAAM,CAAC,WAAW,CAAC,CAAC;IACjG,CAAC;IACD,0FAA0F;IAC1F,KAAK,MAAM,IAAI,IAAI,CAAC,QAAQ,CAAC,MAAM,EAAE,OAAO,QAAQ,CAAC,MAAM,KAAK,QAAQ,CAAC,CAAC,CAAC,GAAG,QAAQ,CAAC,MAAM,gBAAgB,CAAC,CAAC,CAAC,SAAS,EAAE,IAAI,CAAC,MAAM,CAAC;QACrI,IAAI,OAAO,IAAI,KAAK,QAAQ;YAAE,KAAK,CAAC,IAAI,CAAC,OAAO,CAAC,SAAS,EAAE,OAAO,CAAC,IAAI,CAAC,EAAE,IAAI,QAAQ,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC;IACxG,OAAO,KAAK,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,OAAO,CAAC,SAAS,EAAE,IAAI,CAAC,CAAC,CAAC;AACvD,CAAC"}
|
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
import { randomUUID } from 'node:crypto';
|
|
2
|
+
import { mkdir, readFile, rmdir, stat, unlink, writeFile } from 'node:fs/promises';
|
|
3
|
+
import { canonicalPath } from '../core/paths.js';
|
|
4
|
+
import { isSystemError } from '../core/utils.js';
|
|
5
|
+
const INCOMPLETE_LOCK_GRACE_MS = 2000;
|
|
6
|
+
export const databaseLockPath = (path) => `${path}.deep-json-server.lock`;
|
|
7
|
+
const missing = (error) => isSystemError(error) && error.code === 'ENOENT';
|
|
8
|
+
async function ownerOf(path) {
|
|
9
|
+
try {
|
|
10
|
+
const value = JSON.parse(await readFile(path, 'utf8'));
|
|
11
|
+
if (typeof value === 'object' && value !== null && 'pid' in value && 'token' in value && Number.isSafeInteger(value.pid) && typeof value.token === 'string')
|
|
12
|
+
return value;
|
|
13
|
+
}
|
|
14
|
+
catch (error) {
|
|
15
|
+
if (!missing(error) && !(error instanceof SyntaxError))
|
|
16
|
+
throw error;
|
|
17
|
+
}
|
|
18
|
+
return undefined;
|
|
19
|
+
}
|
|
20
|
+
function processExists(pid) {
|
|
21
|
+
if (pid < 1)
|
|
22
|
+
return false;
|
|
23
|
+
try {
|
|
24
|
+
process.kill(pid, 0);
|
|
25
|
+
return true;
|
|
26
|
+
}
|
|
27
|
+
catch (error) {
|
|
28
|
+
if (isSystemError(error) && error.code === 'ESRCH')
|
|
29
|
+
return false;
|
|
30
|
+
if (isSystemError(error) && error.code === 'EPERM')
|
|
31
|
+
return true;
|
|
32
|
+
throw error;
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
async function removeOwnedLock(directory, token) {
|
|
36
|
+
const ownerPath = `${directory}/owner.json`;
|
|
37
|
+
const owner = await ownerOf(ownerPath);
|
|
38
|
+
if (!owner) {
|
|
39
|
+
try {
|
|
40
|
+
await stat(directory);
|
|
41
|
+
}
|
|
42
|
+
catch (error) {
|
|
43
|
+
if (missing(error))
|
|
44
|
+
return;
|
|
45
|
+
throw error;
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
if (owner?.token !== token)
|
|
49
|
+
throw new Error(`Database lock was changed: ${directory}`);
|
|
50
|
+
await unlink(ownerPath);
|
|
51
|
+
await rmdir(directory);
|
|
52
|
+
}
|
|
53
|
+
/** Удерживает блокировку дисковой базы до закрытия сервера и восстанавливает её после остановки процесса. */
|
|
54
|
+
export async function acquireDatabaseLock(databasePath) {
|
|
55
|
+
const path = await canonicalPath(databasePath);
|
|
56
|
+
const directory = databaseLockPath(path);
|
|
57
|
+
const recovery = `${directory}.recovery`;
|
|
58
|
+
const ownerPath = `${directory}/owner.json`;
|
|
59
|
+
const busy = () => new Error(`Database is already in use by another server: ${path}`);
|
|
60
|
+
for (let attempt = 0; attempt < 3; attempt++) {
|
|
61
|
+
try {
|
|
62
|
+
await mkdir(directory);
|
|
63
|
+
const token = randomUUID();
|
|
64
|
+
try {
|
|
65
|
+
await writeFile(ownerPath, JSON.stringify({ pid: process.pid, token }), { flag: 'wx' });
|
|
66
|
+
try {
|
|
67
|
+
await stat(recovery);
|
|
68
|
+
await removeOwnedLock(directory, token);
|
|
69
|
+
continue;
|
|
70
|
+
}
|
|
71
|
+
catch (error) {
|
|
72
|
+
if (!missing(error))
|
|
73
|
+
throw error;
|
|
74
|
+
}
|
|
75
|
+
return () => removeOwnedLock(directory, token);
|
|
76
|
+
}
|
|
77
|
+
catch (error) {
|
|
78
|
+
if ((await ownerOf(ownerPath))?.token === token)
|
|
79
|
+
await removeOwnedLock(directory, token);
|
|
80
|
+
else
|
|
81
|
+
await rmdir(directory).catch(() => undefined);
|
|
82
|
+
throw error;
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
catch (error) {
|
|
86
|
+
if (!isSystemError(error) || error.code !== 'EEXIST')
|
|
87
|
+
throw error;
|
|
88
|
+
}
|
|
89
|
+
const owner = await ownerOf(ownerPath);
|
|
90
|
+
if (owner && processExists(owner.pid))
|
|
91
|
+
throw busy();
|
|
92
|
+
if (!owner && Date.now() - (await stat(directory)).mtimeMs < INCOMPLETE_LOCK_GRACE_MS)
|
|
93
|
+
throw busy();
|
|
94
|
+
try {
|
|
95
|
+
await mkdir(recovery);
|
|
96
|
+
}
|
|
97
|
+
catch (error) {
|
|
98
|
+
if (isSystemError(error) && error.code === 'EEXIST')
|
|
99
|
+
throw busy();
|
|
100
|
+
throw error;
|
|
101
|
+
}
|
|
102
|
+
try {
|
|
103
|
+
const current = await ownerOf(ownerPath);
|
|
104
|
+
if (current && processExists(current.pid))
|
|
105
|
+
throw busy();
|
|
106
|
+
if (current)
|
|
107
|
+
await unlink(ownerPath);
|
|
108
|
+
await rmdir(directory);
|
|
109
|
+
}
|
|
110
|
+
finally {
|
|
111
|
+
await rmdir(recovery);
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
throw busy();
|
|
115
|
+
}
|
|
116
|
+
//# sourceMappingURL=storage-lock.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"storage-lock.js","sourceRoot":"","sources":["../../../src/server/storage-lock.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED