@rocicorp/zero 0.25.0-canary.23 → 0.25.0-canary.24
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/out/analyze-query/src/run-ast.d.ts +1 -1
- package/out/analyze-query/src/run-ast.d.ts.map +1 -1
- package/out/analyze-query/src/run-ast.js +7 -1
- package/out/analyze-query/src/run-ast.js.map +1 -1
- package/out/otel/src/log-options.d.ts +1 -1
- package/out/otel/src/log-options.d.ts.map +1 -1
- package/out/otel/src/log-options.js +0 -1
- package/out/otel/src/log-options.js.map +1 -1
- package/out/shared/src/options-types.d.ts +113 -0
- package/out/shared/src/options-types.d.ts.map +1 -0
- package/out/shared/src/options.d.ts +2 -111
- package/out/shared/src/options.d.ts.map +1 -1
- package/out/shared/src/options.js.map +1 -1
- package/out/zero/package.json.js +1 -1
- package/out/zero/src/pg.js +1 -2
- package/out/zero/src/server.js +1 -2
- package/out/zero/src/zero-cache-dev.js +11 -5
- package/out/zero/src/zero-cache-dev.js.map +1 -1
- package/out/zero/src/zero.js +0 -2
- package/out/zero/src/zero.js.map +1 -1
- package/out/zero-cache/src/auth/read-authorizer.js +1 -1
- package/out/zero-cache/src/auth/read-authorizer.js.map +1 -1
- package/out/zero-cache/src/auth/write-authorizer.js +1 -1
- package/out/zero-cache/src/auth/write-authorizer.js.map +1 -1
- package/out/zero-cache/src/config/zero-config.d.ts.map +1 -1
- package/out/zero-cache/src/config/zero-config.js +5 -3
- package/out/zero-cache/src/config/zero-config.js.map +1 -1
- package/out/zero-cache/src/scripts/deploy-permissions.js +6 -3
- package/out/zero-cache/src/scripts/deploy-permissions.js.map +1 -1
- package/out/zero-cache/src/scripts/permissions.d.ts.map +1 -1
- package/out/zero-cache/src/scripts/permissions.js +11 -13
- package/out/zero-cache/src/scripts/permissions.js.map +1 -1
- package/out/zero-client/src/client/crud.d.ts +3 -2
- package/out/zero-client/src/client/crud.d.ts.map +1 -1
- package/out/zero-client/src/client/crud.js +7 -3
- package/out/zero-client/src/client/crud.js.map +1 -1
- package/out/zero-client/src/client/custom.d.ts +3 -2
- package/out/zero-client/src/client/custom.d.ts.map +1 -1
- package/out/zero-client/src/client/custom.js +2 -2
- package/out/zero-client/src/client/custom.js.map +1 -1
- package/out/zero-client/src/client/make-mutate-property.d.ts +1 -1
- package/out/zero-client/src/client/make-mutate-property.d.ts.map +1 -1
- package/out/zero-client/src/client/make-mutate-property.js +2 -2
- package/out/zero-client/src/client/make-mutate-property.js.map +1 -1
- package/out/zero-client/src/client/mutator-proxy.js +6 -7
- package/out/zero-client/src/client/mutator-proxy.js.map +1 -1
- package/out/zero-client/src/client/version.js +1 -1
- package/out/zero-client/src/client/zero.d.ts +14 -3
- package/out/zero-client/src/client/zero.d.ts.map +1 -1
- package/out/zero-client/src/client/zero.js +19 -6
- package/out/zero-client/src/client/zero.js.map +1 -1
- package/out/zero-client/src/mod.d.ts +3 -4
- package/out/zero-client/src/mod.d.ts.map +1 -1
- package/out/zero-schema/src/compiled-permissions.d.ts +22 -2
- package/out/zero-schema/src/compiled-permissions.d.ts.map +1 -1
- package/out/zero-schema/src/compiled-permissions.js +7 -6
- package/out/zero-schema/src/compiled-permissions.js.map +1 -1
- package/out/zero-schema/src/permissions.d.ts.map +1 -1
- package/out/zero-schema/src/permissions.js.map +1 -1
- package/out/zero-schema/src/schema-config.d.ts +0 -5
- package/out/zero-schema/src/schema-config.d.ts.map +1 -1
- package/out/zero-schema/src/schema-config.js +1 -1
- package/out/zero-schema/src/schema-config.js.map +1 -1
- package/out/zero-server/src/custom.d.ts +5 -14
- package/out/zero-server/src/custom.d.ts.map +1 -1
- package/out/zero-server/src/custom.js +8 -18
- package/out/zero-server/src/custom.js.map +1 -1
- package/out/zql/src/mutate/crud.d.ts +3 -26
- package/out/zql/src/mutate/crud.d.ts.map +1 -1
- package/out/zql/src/mutate/crud.js +14 -26
- package/out/zql/src/mutate/crud.js.map +1 -1
- package/out/zql/src/mutate/custom.d.ts +7 -8
- package/out/zql/src/mutate/custom.d.ts.map +1 -1
- package/out/zql/src/mutate/custom.js.map +1 -1
- package/out/zql/src/planner/planner-join.d.ts.map +1 -1
- package/out/zql/src/planner/planner-join.js +3 -1
- package/out/zql/src/planner/planner-join.js.map +1 -1
- package/package.json +4 -4
|
@@ -2,11 +2,11 @@ import type { LogContext } from '@rocicorp/logger';
|
|
|
2
2
|
import type { LiteAndZqlSpec } from '../../zero-cache/src/db/specs.ts';
|
|
3
3
|
import type { AnalyzeQueryResult } from '../../zero-protocol/src/analyze-query-result.ts';
|
|
4
4
|
import type { AST } from '../../zero-protocol/src/ast.ts';
|
|
5
|
+
import type { ClientSchema } from '../../zero-protocol/src/client-schema.ts';
|
|
5
6
|
import type { PermissionsConfig } from '../../zero-schema/src/compiled-permissions.ts';
|
|
6
7
|
import type { NameMapper } from '../../zero-schema/src/name-mapper.ts';
|
|
7
8
|
import { type BuilderDelegate } from '../../zql/src/builder/builder.ts';
|
|
8
9
|
import type { Database } from '../../zqlite/src/db.ts';
|
|
9
|
-
import type { ClientSchema } from '../../zero-protocol/src/client-schema.ts';
|
|
10
10
|
export type RunAstOptions = {
|
|
11
11
|
applyPermissions?: boolean | undefined;
|
|
12
12
|
authData?: string | undefined;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"run-ast.d.ts","sourceRoot":"","sources":["../../../../analyze-query/src/run-ast.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAC,UAAU,EAAC,MAAM,kBAAkB,CAAC;AAMjD,OAAO,KAAK,EAAC,cAAc,EAAC,MAAM,kCAAkC,CAAC;AAErE,OAAO,KAAK,EAAC,kBAAkB,EAAC,MAAM,iDAAiD,CAAC;AACxF,OAAO,KAAK,EAAC,GAAG,EAAC,MAAM,gCAAgC,CAAC;
|
|
1
|
+
{"version":3,"file":"run-ast.d.ts","sourceRoot":"","sources":["../../../../analyze-query/src/run-ast.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAC,UAAU,EAAC,MAAM,kBAAkB,CAAC;AAMjD,OAAO,KAAK,EAAC,cAAc,EAAC,MAAM,kCAAkC,CAAC;AAErE,OAAO,KAAK,EAAC,kBAAkB,EAAC,MAAM,iDAAiD,CAAC;AACxF,OAAO,KAAK,EAAC,GAAG,EAAC,MAAM,gCAAgC,CAAC;AAExD,OAAO,KAAK,EAAC,YAAY,EAAC,MAAM,0CAA0C,CAAC;AAG3E,OAAO,KAAK,EAAC,iBAAiB,EAAC,MAAM,+CAA+C,CAAC;AACrF,OAAO,KAAK,EAAC,UAAU,EAAC,MAAM,sCAAsC,CAAC;AACrE,OAAO,EAEL,KAAK,eAAe,EACrB,MAAM,kCAAkC,CAAC;AAC1C,OAAO,KAAK,EAAC,QAAQ,EAAC,MAAM,wBAAwB,CAAC;AAErD,MAAM,MAAM,aAAa,GAAG;IAC1B,gBAAgB,CAAC,EAAE,OAAO,GAAG,SAAS,CAAC;IACvC,QAAQ,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IAC9B,oBAAoB,CAAC,EAAE,UAAU,GAAG,SAAS,CAAC;IAC9C,EAAE,EAAE,QAAQ,CAAC;IACb,IAAI,EAAE,eAAe,CAAC;IACtB,WAAW,CAAC,EAAE,iBAAiB,GAAG,SAAS,CAAC;IAC5C,UAAU,CAAC,EAAE,OAAO,GAAG,SAAS,CAAC;IACjC,UAAU,EAAE,GAAG,CAAC,MAAM,EAAE,cAAc,CAAC,CAAC;IACxC,UAAU,CAAC,EAAE,OAAO,GAAG,SAAS,CAAC;CAClC,CAAC;AAEF,wBAAsB,MAAM,CAC1B,EAAE,EAAE,UAAU,EACd,YAAY,EAAE,YAAY,EAC1B,GAAG,EAAE,GAAG,EACR,aAAa,EAAE,OAAO,EACtB,OAAO,EAAE,aAAa,GACrB,OAAO,CAAC,kBAAkB,CAAC,CA6F7B"}
|
|
@@ -24,6 +24,9 @@ async function runAst(lc, clientSchema, ast, isTransformed, options) {
|
|
|
24
24
|
ast = mapAST(ast, must(clientToServerMapper));
|
|
25
25
|
}
|
|
26
26
|
if (options.applyPermissions) {
|
|
27
|
+
result.warnings.push(
|
|
28
|
+
"Permissions are deprecated and will be removed in an upcoming release. See: https://zero.rocicorp.dev/docs/auth."
|
|
29
|
+
);
|
|
27
30
|
const authData = options.authData ? JSON.parse(options.authData) : {};
|
|
28
31
|
if (!options.authData) {
|
|
29
32
|
result.warnings.push(
|
|
@@ -34,7 +37,10 @@ async function runAst(lc, clientSchema, ast, isTransformed, options) {
|
|
|
34
37
|
lc,
|
|
35
38
|
"clientGroupIDForAnalyze",
|
|
36
39
|
ast,
|
|
37
|
-
must(
|
|
40
|
+
must(
|
|
41
|
+
permissions,
|
|
42
|
+
"Permissions are required when applyPermissions is true"
|
|
43
|
+
),
|
|
38
44
|
authData,
|
|
39
45
|
false
|
|
40
46
|
).transformedAst;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"run-ast.js","sources":["../../../../analyze-query/src/run-ast.ts"],"sourcesContent":["import type {LogContext} from '@rocicorp/logger';\nimport {astToZQL} from '../../ast-to-zql/src/ast-to-zql.ts';\nimport {formatOutput} from '../../ast-to-zql/src/format.ts';\nimport {assert} from '../../shared/src/asserts.ts';\nimport {must} from '../../shared/src/must.ts';\nimport {transformAndHashQuery} from '../../zero-cache/src/auth/read-authorizer.ts';\nimport type {LiteAndZqlSpec} from '../../zero-cache/src/db/specs.ts';\nimport {hydrate} from '../../zero-cache/src/services/view-syncer/pipeline-driver.ts';\nimport type {AnalyzeQueryResult} from '../../zero-protocol/src/analyze-query-result.ts';\nimport type {AST} from '../../zero-protocol/src/ast.ts';\nimport {mapAST} from '../../zero-protocol/src/ast.ts';\nimport type {Row} from '../../zero-protocol/src/data.ts';\nimport {hashOfAST} from '../../zero-protocol/src/query-hash.ts';\nimport type {PermissionsConfig} from '../../zero-schema/src/compiled-permissions.ts';\nimport type {NameMapper} from '../../zero-schema/src/name-mapper.ts';\nimport {\n buildPipeline,\n type BuilderDelegate,\n} from '../../zql/src/builder/builder.ts';\nimport type {Database} from '../../zqlite/src/db.ts';\
|
|
1
|
+
{"version":3,"file":"run-ast.js","sources":["../../../../analyze-query/src/run-ast.ts"],"sourcesContent":["import type {LogContext} from '@rocicorp/logger';\nimport {astToZQL} from '../../ast-to-zql/src/ast-to-zql.ts';\nimport {formatOutput} from '../../ast-to-zql/src/format.ts';\nimport {assert} from '../../shared/src/asserts.ts';\nimport {must} from '../../shared/src/must.ts';\nimport {transformAndHashQuery} from '../../zero-cache/src/auth/read-authorizer.ts';\nimport type {LiteAndZqlSpec} from '../../zero-cache/src/db/specs.ts';\nimport {hydrate} from '../../zero-cache/src/services/view-syncer/pipeline-driver.ts';\nimport type {AnalyzeQueryResult} from '../../zero-protocol/src/analyze-query-result.ts';\nimport type {AST} from '../../zero-protocol/src/ast.ts';\nimport {mapAST} from '../../zero-protocol/src/ast.ts';\nimport type {ClientSchema} from '../../zero-protocol/src/client-schema.ts';\nimport type {Row} from '../../zero-protocol/src/data.ts';\nimport {hashOfAST} from '../../zero-protocol/src/query-hash.ts';\nimport type {PermissionsConfig} from '../../zero-schema/src/compiled-permissions.ts';\nimport type {NameMapper} from '../../zero-schema/src/name-mapper.ts';\nimport {\n buildPipeline,\n type BuilderDelegate,\n} from '../../zql/src/builder/builder.ts';\nimport type {Database} from '../../zqlite/src/db.ts';\n\nexport type RunAstOptions = {\n applyPermissions?: boolean | undefined;\n authData?: string | undefined;\n clientToServerMapper?: NameMapper | undefined;\n db: Database;\n host: BuilderDelegate;\n permissions?: PermissionsConfig | undefined;\n syncedRows?: boolean | undefined;\n tableSpecs: Map<string, LiteAndZqlSpec>;\n vendedRows?: boolean | undefined;\n};\n\nexport async function runAst(\n lc: LogContext,\n clientSchema: ClientSchema,\n ast: AST,\n isTransformed: boolean,\n options: RunAstOptions,\n): Promise<AnalyzeQueryResult> {\n const {clientToServerMapper, permissions, host} = options;\n const result: AnalyzeQueryResult = {\n warnings: [],\n syncedRows: undefined,\n syncedRowCount: 0,\n start: 0,\n end: 0,\n afterPermissions: undefined,\n readRows: undefined,\n readRowCountsByQuery: {},\n readRowCount: undefined,\n };\n\n if (!isTransformed) {\n // map the AST to server names if not already transformed\n ast = mapAST(ast, must(clientToServerMapper));\n }\n if (options.applyPermissions) {\n result.warnings.push(\n 'Permissions are deprecated and will be removed in an upcoming release. See: https://zero.rocicorp.dev/docs/auth.',\n );\n\n const authData = options.authData ? JSON.parse(options.authData) : {};\n if (!options.authData) {\n result.warnings.push(\n 'No auth data provided. Permission rules will compare to `NULL` wherever an auth data field is referenced.',\n );\n }\n ast = transformAndHashQuery(\n lc,\n 'clientGroupIDForAnalyze',\n ast,\n must(\n permissions,\n 'Permissions are required when applyPermissions is true',\n ),\n authData,\n false,\n ).transformedAst;\n result.afterPermissions = await formatOutput(ast.table + astToZQL(ast));\n }\n const pipeline = buildPipeline(ast, host, 'query-id');\n\n const start = performance.now();\n\n let syncedRowCount = 0;\n const rowsByTable: Record<string, Row[]> = {};\n const seenByTable: Set<string> = new Set();\n for (const rowChange of hydrate(pipeline, hashOfAST(ast), clientSchema)) {\n if (rowChange === 'yield') {\n continue;\n }\n assert(rowChange.type === 'add');\n\n let rows: Row[] = rowsByTable[rowChange.table];\n const s = rowChange.table + '.' + JSON.stringify(rowChange.row);\n if (seenByTable.has(s)) {\n continue; // skip duplicates\n }\n syncedRowCount++;\n seenByTable.add(s);\n if (options.syncedRows) {\n if (!rows) {\n rows = [];\n rowsByTable[rowChange.table] = rows;\n }\n rows.push(rowChange.row);\n }\n }\n\n const end = performance.now();\n if (options.syncedRows) {\n result.syncedRows = rowsByTable;\n }\n result.start = start;\n result.end = end;\n\n // Always include the count of synced and vended rows.\n result.syncedRowCount = syncedRowCount;\n result.readRowCountsByQuery = host.debug?.getVendedRowCounts() ?? {};\n let readRowCount = 0;\n for (const c of Object.values(result.readRowCountsByQuery)) {\n for (const v of Object.values(c)) {\n readRowCount += v;\n }\n }\n result.readRowCount = readRowCount;\n\n if (options.vendedRows) {\n result.readRows = host.debug?.getVendedRows();\n }\n return result;\n}\n"],"names":[],"mappings":";;;;;;;;;AAkCA,eAAsB,OACpB,IACA,cACA,KACA,eACA,SAC6B;AAC7B,QAAM,EAAC,sBAAsB,aAAa,KAAA,IAAQ;AAClD,QAAM,SAA6B;AAAA,IACjC,UAAU,CAAA;AAAA,IACV,YAAY;AAAA,IACZ,gBAAgB;AAAA,IAChB,OAAO;AAAA,IACP,KAAK;AAAA,IACL,kBAAkB;AAAA,IAClB,UAAU;AAAA,IACV,sBAAsB,CAAA;AAAA,IACtB,cAAc;AAAA,EAAA;AAGhB,MAAI,CAAC,eAAe;AAElB,UAAM,OAAO,KAAK,KAAK,oBAAoB,CAAC;AAAA,EAC9C;AACA,MAAI,QAAQ,kBAAkB;AAC5B,WAAO,SAAS;AAAA,MACd;AAAA,IAAA;AAGF,UAAM,WAAW,QAAQ,WAAW,KAAK,MAAM,QAAQ,QAAQ,IAAI,CAAA;AACnE,QAAI,CAAC,QAAQ,UAAU;AACrB,aAAO,SAAS;AAAA,QACd;AAAA,MAAA;AAAA,IAEJ;AACA,UAAM;AAAA,MACJ;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,QACE;AAAA,QACA;AAAA,MAAA;AAAA,MAEF;AAAA,MACA;AAAA,IAAA,EACA;AACF,WAAO,mBAAmB,MAAM,aAAa,IAAI,QAAQ,SAAS,GAAG,CAAC;AAAA,EACxE;AACA,QAAM,WAAW,cAAc,KAAK,MAAM,UAAU;AAEpD,QAAM,QAAQ,YAAY,IAAA;AAE1B,MAAI,iBAAiB;AACrB,QAAM,cAAqC,CAAA;AAC3C,QAAM,kCAA+B,IAAA;AACrC,aAAW,aAAa,QAAQ,UAAU,UAAU,GAAG,GAAG,YAAY,GAAG;AACvE,QAAI,cAAc,SAAS;AACzB;AAAA,IACF;AACA,WAAO,UAAU,SAAS,KAAK;AAE/B,QAAI,OAAc,YAAY,UAAU,KAAK;AAC7C,UAAM,IAAI,UAAU,QAAQ,MAAM,KAAK,UAAU,UAAU,GAAG;AAC9D,QAAI,YAAY,IAAI,CAAC,GAAG;AACtB;AAAA,IACF;AACA;AACA,gBAAY,IAAI,CAAC;AACjB,QAAI,QAAQ,YAAY;AACtB,UAAI,CAAC,MAAM;AACT,eAAO,CAAA;AACP,oBAAY,UAAU,KAAK,IAAI;AAAA,MACjC;AACA,WAAK,KAAK,UAAU,GAAG;AAAA,IACzB;AAAA,EACF;AAEA,QAAM,MAAM,YAAY,IAAA;AACxB,MAAI,QAAQ,YAAY;AACtB,WAAO,aAAa;AAAA,EACtB;AACA,SAAO,QAAQ;AACf,SAAO,MAAM;AAGb,SAAO,iBAAiB;AACxB,SAAO,uBAAuB,KAAK,OAAO,mBAAA,KAAwB,CAAA;AAClE,MAAI,eAAe;AACnB,aAAW,KAAK,OAAO,OAAO,OAAO,oBAAoB,GAAG;AAC1D,eAAW,KAAK,OAAO,OAAO,CAAC,GAAG;AAChC,sBAAgB;AAAA,IAClB;AAAA,EACF;AACA,SAAO,eAAe;AAEtB,MAAI,QAAQ,YAAY;AACtB,WAAO,WAAW,KAAK,OAAO,cAAA;AAAA,EAChC;AACA,SAAO;AACT;"}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { type Config } from '../../shared/src/options.ts';
|
|
1
|
+
import { type Config } from '../../shared/src/options-types.ts';
|
|
2
2
|
import * as v from '../../shared/src/valita.ts';
|
|
3
3
|
export declare const logLevel: v.Type<"error" | "debug" | "info" | "warn">;
|
|
4
4
|
export declare const logOptions: {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"log-options.d.ts","sourceRoot":"","sources":["../../../../otel/src/log-options.ts"],"names":[],"mappings":"AAAA,OAAO,EAAC,KAAK,MAAM,EAAC,MAAM,
|
|
1
|
+
{"version":3,"file":"log-options.d.ts","sourceRoot":"","sources":["../../../../otel/src/log-options.ts"],"names":[],"mappings":"AAAA,OAAO,EAAC,KAAK,MAAM,EAAC,MAAM,mCAAmC,CAAC;AAC9D,OAAO,KAAK,CAAC,MAAM,4BAA4B,CAAC;AAEhD,eAAO,MAAM,QAAQ,6CAAmD,CAAC;AAEzE,eAAO,MAAM,UAAU;;;;;;;;;;;;;;;;;;CA+BtB,CAAC;AAEF,MAAM,MAAM,SAAS,GAAG,MAAM,CAAC,OAAO,UAAU,CAAC,CAAC"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"log-options.js","sources":["../../../../otel/src/log-options.ts"],"sourcesContent":["import {type Config} from '../../shared/src/options.ts';\nimport * as v from '../../shared/src/valita.ts';\n\nexport const logLevel = v.literalUnion('debug', 'info', 'warn', 'error');\n\nexport const logOptions = {\n level: logLevel.default('info'),\n\n format: {\n type: v.literalUnion('text', 'json').default('text'),\n desc: [\n `Use {bold text} for developer-friendly console logging`,\n `and {bold json} for consumption by structured-logging services`,\n ],\n },\n\n slowRowThreshold: {\n type: v.number().default(2),\n desc: [\n `The number of ms a row must take to fetch from table-source before it is considered slow.`,\n ],\n },\n\n slowHydrateThreshold: {\n type: v.number().default(100),\n desc: [\n `The number of milliseconds a query hydration must take to print a slow warning.`,\n ],\n },\n\n ivmSampling: {\n type: v.number().default(5000),\n desc: [\n `How often to collect IVM metrics. 1 out of N requests will be sampled where N is this value.`,\n ],\n },\n};\n\nexport type LogConfig = Config<typeof logOptions>;\n"],"names":["v.literalUnion","v.number"],"mappings":"
|
|
1
|
+
{"version":3,"file":"log-options.js","sources":["../../../../otel/src/log-options.ts"],"sourcesContent":["import {type Config} from '../../shared/src/options-types.ts';\nimport * as v from '../../shared/src/valita.ts';\n\nexport const logLevel = v.literalUnion('debug', 'info', 'warn', 'error');\n\nexport const logOptions = {\n level: logLevel.default('info'),\n\n format: {\n type: v.literalUnion('text', 'json').default('text'),\n desc: [\n `Use {bold text} for developer-friendly console logging`,\n `and {bold json} for consumption by structured-logging services`,\n ],\n },\n\n slowRowThreshold: {\n type: v.number().default(2),\n desc: [\n `The number of ms a row must take to fetch from table-source before it is considered slow.`,\n ],\n },\n\n slowHydrateThreshold: {\n type: v.number().default(100),\n desc: [\n `The number of milliseconds a query hydration must take to print a slow warning.`,\n ],\n },\n\n ivmSampling: {\n type: v.number().default(5000),\n desc: [\n `How often to collect IVM metrics. 1 out of N requests will be sampled where N is this value.`,\n ],\n },\n};\n\nexport type LogConfig = Config<typeof logOptions>;\n"],"names":["v.literalUnion","v.number"],"mappings":";;AAGO,MAAM,WAAWA,aAAe,SAAS,QAAQ,QAAQ,OAAO;AAEhE,MAAM,aAAa;AAAA,EACxB,OAAO,SAAS,QAAQ,MAAM;AAAA,EAE9B,QAAQ;AAAA,IACN,MAAMA,aAAe,QAAQ,MAAM,EAAE,QAAQ,MAAM;AAAA,IACnD,MAAM;AAAA,MACJ;AAAA,MACA;AAAA,IAAA;AAAA,EACF;AAAA,EAGF,kBAAkB;AAAA,IAChB,MAAMC,OAAE,EAAS,QAAQ,CAAC;AAAA,IAC1B,MAAM;AAAA,MACJ;AAAA,IAAA;AAAA,EACF;AAAA,EAGF,sBAAsB;AAAA,IACpB,MAAMA,OAAE,EAAS,QAAQ,GAAG;AAAA,IAC5B,MAAM;AAAA,MACJ;AAAA,IAAA;AAAA,EACF;AAAA,EAGF,aAAa;AAAA,IACX,MAAMA,OAAE,EAAS,QAAQ,GAAI;AAAA,IAC7B,MAAM;AAAA,MACJ;AAAA,IAAA;AAAA,EACF;AAEJ;"}
|
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
import type * as v from './valita.ts';
|
|
2
|
+
type RequiredOptionType = v.Type<string> | v.Type<number> | v.Type<boolean> | v.Type<string[]> | v.Type<number[]> | v.Type<boolean[]>;
|
|
3
|
+
type OptionalOptionType = v.Optional<string> | v.Optional<number> | v.Optional<boolean> | v.Optional<string[]> | v.Optional<number[]> | v.Optional<boolean[]>;
|
|
4
|
+
type OptionType = RequiredOptionType | OptionalOptionType;
|
|
5
|
+
export type WrappedOptionType = {
|
|
6
|
+
type: OptionType;
|
|
7
|
+
/** Description lines to be displayed in --help. */
|
|
8
|
+
desc?: string[];
|
|
9
|
+
/** Logged as a warning when parsed. */
|
|
10
|
+
deprecated?: string[];
|
|
11
|
+
/** One-character alias for getopt-style short flags, e.g. -m */
|
|
12
|
+
alias?: string;
|
|
13
|
+
/**
|
|
14
|
+
* Exclude this flag from --help text. Used for internal flags.
|
|
15
|
+
* Deprecated options are hidden by default.
|
|
16
|
+
*/
|
|
17
|
+
hidden?: boolean;
|
|
18
|
+
};
|
|
19
|
+
export type Option = OptionType | WrappedOptionType;
|
|
20
|
+
export type Group = Record<string, Option>;
|
|
21
|
+
/**
|
|
22
|
+
* # Options
|
|
23
|
+
*
|
|
24
|
+
* An `Options` object specifies of a set of (possibly grouped) configuration
|
|
25
|
+
* values that are parsed from environment variables and/or command line flags.
|
|
26
|
+
*
|
|
27
|
+
* Each option is represented by a `valita` schema object. The `Options`
|
|
28
|
+
* type supports one level of grouping for organizing related options.
|
|
29
|
+
*
|
|
30
|
+
* ```ts
|
|
31
|
+
* {
|
|
32
|
+
* port: v.number().default(8080),
|
|
33
|
+
*
|
|
34
|
+
* numWorkers: v.number(),
|
|
35
|
+
*
|
|
36
|
+
* log: {
|
|
37
|
+
* level: v.union(v.literal('debug'), v.literal('info'), ...),
|
|
38
|
+
* format: v.union(v.literal('text'), v.literal('json')).default('text'),
|
|
39
|
+
* }
|
|
40
|
+
* }
|
|
41
|
+
* ```
|
|
42
|
+
*
|
|
43
|
+
* {@link parseOptions()} will use an `Options` object to populate a {@link Config}
|
|
44
|
+
* instance of the corresponding shape, consulting SNAKE_CASE environment variables
|
|
45
|
+
* and/or camelCase command line flags, with flags taking precedence, based on the field
|
|
46
|
+
* (and group) names:
|
|
47
|
+
*
|
|
48
|
+
* | Option | Flag | Env |
|
|
49
|
+
* | -------------- | ------------- | ----------- |
|
|
50
|
+
* | port | --port | PORT |
|
|
51
|
+
* | numWorkers | --num-workers | NUM_WORKERS |
|
|
52
|
+
* | log: { level } | --log-level | LOG_LEVEL |
|
|
53
|
+
* | log: { format } | --log-format | LOG_FORMAT |
|
|
54
|
+
*
|
|
55
|
+
* `Options` supports:
|
|
56
|
+
* * primitive valita types `string`, `number`, `boolean`
|
|
57
|
+
* * single-type arrays or tuples of primitives
|
|
58
|
+
* * optional values
|
|
59
|
+
* * default values
|
|
60
|
+
*
|
|
61
|
+
* ### Additional Flag Configuration
|
|
62
|
+
*
|
|
63
|
+
* {@link parseOptions()} will generate a usage guide that is displayed for
|
|
64
|
+
* the `--help` or `-h` flags, displaying the flag name, env name, value
|
|
65
|
+
* type (or enumeration), and default values based on the valita schema.
|
|
66
|
+
*
|
|
67
|
+
* For additional configuration, each object can instead by represented by
|
|
68
|
+
* a {@link WrappedOptionType}, where the valita schema is held in the `type`
|
|
69
|
+
* field, along with additional optional fields:
|
|
70
|
+
* * `desc` for documentation displayed in `--help`
|
|
71
|
+
* * `alias` for getopt-style short flags like `-m`
|
|
72
|
+
*/
|
|
73
|
+
export type Options = Record<string, Group | Option>;
|
|
74
|
+
/** Unwrap the Value type from an Option<V>. */
|
|
75
|
+
type ValueOf<T extends Option> = T extends v.Optional<infer V> ? V | undefined : T extends v.Type<infer V> ? V : T extends WrappedOptionType ? ValueOf<T['type']> : never;
|
|
76
|
+
type Required = RequiredOptionType | (WrappedOptionType & {
|
|
77
|
+
type: RequiredOptionType;
|
|
78
|
+
});
|
|
79
|
+
type Optional = OptionalOptionType | (WrappedOptionType & {
|
|
80
|
+
type: OptionalOptionType;
|
|
81
|
+
});
|
|
82
|
+
type ConfigGroup<G extends Group> = {
|
|
83
|
+
[P in keyof G as G[P] extends Required ? P : never]: ValueOf<G[P]>;
|
|
84
|
+
} & {
|
|
85
|
+
[P in keyof G as G[P] extends Optional ? P : never]?: ValueOf<G[P]>;
|
|
86
|
+
};
|
|
87
|
+
/**
|
|
88
|
+
* A Config is an object containing values parsed from an {@link Options} object.
|
|
89
|
+
*
|
|
90
|
+
* Example:
|
|
91
|
+
*
|
|
92
|
+
* ```ts
|
|
93
|
+
* {
|
|
94
|
+
* port: number;
|
|
95
|
+
*
|
|
96
|
+
* numWorkers: number;
|
|
97
|
+
*
|
|
98
|
+
* // The "log" group
|
|
99
|
+
* log: {
|
|
100
|
+
* level: 'debug' | 'info' | 'warn' | 'error';
|
|
101
|
+
* format: 'text' | 'json'
|
|
102
|
+
* };
|
|
103
|
+
* ...
|
|
104
|
+
* }
|
|
105
|
+
* ```
|
|
106
|
+
*/
|
|
107
|
+
export type Config<O extends Options> = {
|
|
108
|
+
[P in keyof O as O[P] extends Required | Group ? P : never]: O[P] extends Required ? ValueOf<O[P]> : O[P] extends Group ? ConfigGroup<O[P]> : never;
|
|
109
|
+
} & {
|
|
110
|
+
[P in keyof O as O[P] extends Optional ? P : never]?: O[P] extends Optional ? ValueOf<O[P]> : never;
|
|
111
|
+
};
|
|
112
|
+
export {};
|
|
113
|
+
//# sourceMappingURL=options-types.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"options-types.d.ts","sourceRoot":"","sources":["../../../../shared/src/options-types.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,115 +1,7 @@
|
|
|
1
1
|
import type { OptionalLogger } from '@rocicorp/logger';
|
|
2
|
+
import type { Config, Group, Option, Options, WrappedOptionType } from './options-types.ts';
|
|
2
3
|
import * as v from './valita.ts';
|
|
3
|
-
type
|
|
4
|
-
type OptionalOptionType = v.Optional<string> | v.Optional<number> | v.Optional<boolean> | v.Optional<string[]> | v.Optional<number[]> | v.Optional<boolean[]>;
|
|
5
|
-
type OptionType = RequiredOptionType | OptionalOptionType;
|
|
6
|
-
export type WrappedOptionType = {
|
|
7
|
-
type: OptionType;
|
|
8
|
-
/** Description lines to be displayed in --help. */
|
|
9
|
-
desc?: string[];
|
|
10
|
-
/** Logged as a warning when parsed. */
|
|
11
|
-
deprecated?: string[];
|
|
12
|
-
/** One-character alias for getopt-style short flags, e.g. -m */
|
|
13
|
-
alias?: string;
|
|
14
|
-
/**
|
|
15
|
-
* Exclude this flag from --help text. Used for internal flags.
|
|
16
|
-
* Deprecated options are hidden by default.
|
|
17
|
-
*/
|
|
18
|
-
hidden?: boolean;
|
|
19
|
-
};
|
|
20
|
-
export type Option = OptionType | WrappedOptionType;
|
|
21
|
-
export type Group = Record<string, Option>;
|
|
22
|
-
/**
|
|
23
|
-
* # Options
|
|
24
|
-
*
|
|
25
|
-
* An `Options` object specifies of a set of (possibly grouped) configuration
|
|
26
|
-
* values that are parsed from environment variables and/or command line flags.
|
|
27
|
-
*
|
|
28
|
-
* Each option is represented by a `valita` schema object. The `Options`
|
|
29
|
-
* type supports one level of grouping for organizing related options.
|
|
30
|
-
*
|
|
31
|
-
* ```ts
|
|
32
|
-
* {
|
|
33
|
-
* port: v.number().default(8080),
|
|
34
|
-
*
|
|
35
|
-
* numWorkers: v.number(),
|
|
36
|
-
*
|
|
37
|
-
* log: {
|
|
38
|
-
* level: v.union(v.literal('debug'), v.literal('info'), ...),
|
|
39
|
-
* format: v.union(v.literal('text'), v.literal('json')).default('text'),
|
|
40
|
-
* }
|
|
41
|
-
* }
|
|
42
|
-
* ```
|
|
43
|
-
*
|
|
44
|
-
* {@link parseOptions()} will use an `Options` object to populate a {@link Config}
|
|
45
|
-
* instance of the corresponding shape, consulting SNAKE_CASE environment variables
|
|
46
|
-
* and/or camelCase command line flags, with flags taking precedence, based on the field
|
|
47
|
-
* (and group) names:
|
|
48
|
-
*
|
|
49
|
-
* | Option | Flag | Env |
|
|
50
|
-
* | -------------- | ------------- | ----------- |
|
|
51
|
-
* | port | --port | PORT |
|
|
52
|
-
* | numWorkers | --num-workers | NUM_WORKERS |
|
|
53
|
-
* | log: { level } | --log-level | LOG_LEVEL |
|
|
54
|
-
* | log: { format } | --log-format | LOG_FORMAT |
|
|
55
|
-
*
|
|
56
|
-
* `Options` supports:
|
|
57
|
-
* * primitive valita types `string`, `number`, `boolean`
|
|
58
|
-
* * single-type arrays or tuples of primitives
|
|
59
|
-
* * optional values
|
|
60
|
-
* * default values
|
|
61
|
-
*
|
|
62
|
-
* ### Additional Flag Configuration
|
|
63
|
-
*
|
|
64
|
-
* {@link parseOptions()} will generate a usage guide that is displayed for
|
|
65
|
-
* the `--help` or `-h` flags, displaying the flag name, env name, value
|
|
66
|
-
* type (or enumeration), and default values based on the valita schema.
|
|
67
|
-
*
|
|
68
|
-
* For additional configuration, each object can instead by represented by
|
|
69
|
-
* a {@link WrappedOptionType}, where the valita schema is held in the `type`
|
|
70
|
-
* field, along with additional optional fields:
|
|
71
|
-
* * `desc` for documentation displayed in `--help`
|
|
72
|
-
* * `alias` for getopt-style short flags like `-m`
|
|
73
|
-
*/
|
|
74
|
-
export type Options = Record<string, Group | Option>;
|
|
75
|
-
/** Unwrap the Value type from an Option<V>. */
|
|
76
|
-
type ValueOf<T extends Option> = T extends v.Optional<infer V> ? V | undefined : T extends v.Type<infer V> ? V : T extends WrappedOptionType ? ValueOf<T['type']> : never;
|
|
77
|
-
type Required = RequiredOptionType | (WrappedOptionType & {
|
|
78
|
-
type: RequiredOptionType;
|
|
79
|
-
});
|
|
80
|
-
type Optional = OptionalOptionType | (WrappedOptionType & {
|
|
81
|
-
type: OptionalOptionType;
|
|
82
|
-
});
|
|
83
|
-
type ConfigGroup<G extends Group> = {
|
|
84
|
-
[P in keyof G as G[P] extends Required ? P : never]: ValueOf<G[P]>;
|
|
85
|
-
} & {
|
|
86
|
-
[P in keyof G as G[P] extends Optional ? P : never]?: ValueOf<G[P]>;
|
|
87
|
-
};
|
|
88
|
-
/**
|
|
89
|
-
* A Config is an object containing values parsed from an {@link Options} object.
|
|
90
|
-
*
|
|
91
|
-
* Example:
|
|
92
|
-
*
|
|
93
|
-
* ```ts
|
|
94
|
-
* {
|
|
95
|
-
* port: number;
|
|
96
|
-
*
|
|
97
|
-
* numWorkers: number;
|
|
98
|
-
*
|
|
99
|
-
* // The "log" group
|
|
100
|
-
* log: {
|
|
101
|
-
* level: 'debug' | 'info' | 'warn' | 'error';
|
|
102
|
-
* format: 'text' | 'json'
|
|
103
|
-
* };
|
|
104
|
-
* ...
|
|
105
|
-
* }
|
|
106
|
-
* ```
|
|
107
|
-
*/
|
|
108
|
-
export type Config<O extends Options> = {
|
|
109
|
-
[P in keyof O as O[P] extends Required | Group ? P : never]: O[P] extends Required ? ValueOf<O[P]> : O[P] extends Group ? ConfigGroup<O[P]> : never;
|
|
110
|
-
} & {
|
|
111
|
-
[P in keyof O as O[P] extends Optional ? P : never]?: O[P] extends Optional ? ValueOf<O[P]> : never;
|
|
112
|
-
};
|
|
4
|
+
export type { Config, Group, Option, Options, WrappedOptionType };
|
|
113
5
|
/**
|
|
114
6
|
* Converts an Options instance into an "env schema", which is an object with
|
|
115
7
|
* ENV names as its keys, mapped to optional or required string values
|
|
@@ -151,5 +43,4 @@ export declare function parseOptionsAdvanced<T extends Options>(appOptions: T, o
|
|
|
151
43
|
unknown?: string[];
|
|
152
44
|
};
|
|
153
45
|
export declare function parseBoolean(optionName: string, input: string): boolean;
|
|
154
|
-
export {};
|
|
155
46
|
//# sourceMappingURL=options.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"options.d.ts","sourceRoot":"","sources":["../../../../shared/src/options.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAC,cAAc,EAAC,MAAM,kBAAkB,CAAC;AAUrD,OAAO,KAAK,
|
|
1
|
+
{"version":3,"file":"options.d.ts","sourceRoot":"","sources":["../../../../shared/src/options.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAC,cAAc,EAAC,MAAM,kBAAkB,CAAC;AAUrD,OAAO,KAAK,EACV,MAAM,EACN,KAAK,EACL,MAAM,EACN,OAAO,EACP,iBAAiB,EAClB,MAAM,oBAAoB,CAAC;AAC5B,OAAO,KAAK,CAAC,MAAM,aAAa,CAAC;AAEjC,YAAY,EAAC,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,OAAO,EAAE,iBAAiB,EAAC,CAAC;AAiFhE;;;;;;;GAOG;AACH,wBAAgB,SAAS,CAAC,CAAC,SAAS,OAAO,EAAE,OAAO,EAAE,CAAC,EAAE,aAAa,SAAK;;cAgC1E;AAeD,MAAM,MAAM,YAAY,GAAG;IACzB,wCAAwC;IACxC,IAAI,CAAC,EAAE,MAAM,EAAE,CAAC;IAEhB,aAAa,CAAC,EAAE,MAAM,CAAC;IAEvB,WAAW,CAAC,EAAE;QAAC,MAAM,EAAE,MAAM,CAAC;QAAC,OAAO,EAAE,MAAM,CAAA;KAAC,EAAE,CAAC;IAElD,0BAA0B;IAC1B,YAAY,CAAC,EAAE,OAAO,CAAC;IAEvB,0BAA0B;IAC1B,YAAY,CAAC,EAAE,OAAO,CAAC;IAEvB,iCAAiC;IACjC,GAAG,CAAC,EAAE,MAAM,CAAC,UAAU,CAAC;IAExB,0BAA0B;IAC1B,uBAAuB,CAAC,EAAE,OAAO,CAAC;IAElC,sGAAsG;IACtG,eAAe,CAAC,EAAE,OAAO,CAAC;IAE1B,4BAA4B;IAC5B,MAAM,CAAC,EAAE,cAAc,CAAC;IAExB,iCAAiC;IACjC,IAAI,CAAC,EAAE,CAAC,IAAI,CAAC,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,KAAK,KAAK,CAAC;CACjD,CAAC;AAEF,wBAAgB,YAAY,CAAC,CAAC,SAAS,OAAO,EAC5C,UAAU,EAAE,CAAC,EACb,IAAI,GAAE,YAAiB,GACtB,MAAM,CAAC,CAAC,CAAC,CAEX;AAED,wBAAgB,oBAAoB,CAAC,CAAC,SAAS,OAAO,EACpD,UAAU,EAAE,CAAC,EACb,IAAI,GAAE,YAAiB,GACtB;IAAC,MAAM,EAAE,MAAM,CAAC,CAAC,CAAC,CAAC;IAAC,GAAG,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAAC,OAAO,CAAC,EAAE,MAAM,EAAE,CAAA;CAAC,CA0KtE;AA6FD,wBAAgB,YAAY,CAAC,UAAU,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,WAQ7D"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"options.js","sources":["../../../../shared/src/options.ts"],"sourcesContent":["import type {OptionalLogger} from '@rocicorp/logger';\nimport {template} from 'chalk-template';\nimport type {OptionDefinition} from 'command-line-args';\nimport commandLineArgs from 'command-line-args';\nimport commandLineUsage, {type Section} from 'command-line-usage';\nimport {createDefu} from 'defu';\nimport {toKebabCase, toSnakeCase} from 'kasi';\nimport {stripVTControlCharacters as stripAnsi} from 'node:util';\nimport {assert} from './asserts.ts';\nimport {must} from './must.ts';\nimport * as v from './valita.ts';\n\ntype Primitive = number | string | boolean;\ntype Value = Primitive | Array<Primitive>;\n\ntype RequiredOptionType =\n | v.Type<string>\n | v.Type<number>\n | v.Type<boolean>\n | v.Type<string[]>\n | v.Type<number[]>\n | v.Type<boolean[]>;\n\ntype OptionalOptionType =\n | v.Optional<string>\n | v.Optional<number>\n | v.Optional<boolean>\n | v.Optional<string[]>\n | v.Optional<number[]>\n | v.Optional<boolean[]>;\n\ntype OptionType = RequiredOptionType | OptionalOptionType;\n\nexport type WrappedOptionType = {\n type: OptionType;\n\n /** Description lines to be displayed in --help. */\n desc?: string[];\n\n /** Logged as a warning when parsed. */\n deprecated?: string[];\n\n /** One-character alias for getopt-style short flags, e.g. -m */\n alias?: string;\n\n /**\n * Exclude this flag from --help text. Used for internal flags.\n * Deprecated options are hidden by default.\n */\n hidden?: boolean;\n};\n\nexport type Option = OptionType | WrappedOptionType;\n\n// Related Options can be grouped.\nexport type Group = Record<string, Option>;\n\n/**\n * # Options\n *\n * An `Options` object specifies of a set of (possibly grouped) configuration\n * values that are parsed from environment variables and/or command line flags.\n *\n * Each option is represented by a `valita` schema object. The `Options`\n * type supports one level of grouping for organizing related options.\n *\n * ```ts\n * {\n * port: v.number().default(8080),\n *\n * numWorkers: v.number(),\n *\n * log: {\n * level: v.union(v.literal('debug'), v.literal('info'), ...),\n * format: v.union(v.literal('text'), v.literal('json')).default('text'),\n * }\n * }\n * ```\n *\n * {@link parseOptions()} will use an `Options` object to populate a {@link Config}\n * instance of the corresponding shape, consulting SNAKE_CASE environment variables\n * and/or camelCase command line flags, with flags taking precedence, based on the field\n * (and group) names:\n *\n * | Option | Flag | Env |\n * | -------------- | ------------- | ----------- |\n * | port | --port | PORT |\n * | numWorkers | --num-workers | NUM_WORKERS |\n * | log: { level } | --log-level | LOG_LEVEL |\n * | log: { format } | --log-format | LOG_FORMAT |\n *\n * `Options` supports:\n * * primitive valita types `string`, `number`, `boolean`\n * * single-type arrays or tuples of primitives\n * * optional values\n * * default values\n *\n * ### Additional Flag Configuration\n *\n * {@link parseOptions()} will generate a usage guide that is displayed for\n * the `--help` or `-h` flags, displaying the flag name, env name, value\n * type (or enumeration), and default values based on the valita schema.\n *\n * For additional configuration, each object can instead by represented by\n * a {@link WrappedOptionType}, where the valita schema is held in the `type`\n * field, along with additional optional fields:\n * * `desc` for documentation displayed in `--help`\n * * `alias` for getopt-style short flags like `-m`\n */\nexport type Options = Record<string, Group | Option>;\n\n/** Unwrap the Value type from an Option<V>. */\ntype ValueOf<T extends Option> =\n T extends v.Optional<infer V>\n ? V | undefined\n : T extends v.Type<infer V>\n ? V\n : T extends WrappedOptionType\n ? ValueOf<T['type']>\n : never;\n\ntype Required =\n | RequiredOptionType\n | (WrappedOptionType & {type: RequiredOptionType});\ntype Optional =\n | OptionalOptionType\n | (WrappedOptionType & {type: OptionalOptionType});\n\n// Type the fields for optional options as `field?`\ntype ConfigGroup<G extends Group> = {\n [P in keyof G as G[P] extends Required ? P : never]: ValueOf<G[P]>;\n} & {\n // Values for optional options are in optional fields.\n [P in keyof G as G[P] extends Optional ? P : never]?: ValueOf<G[P]>;\n};\n\n/**\n * A Config is an object containing values parsed from an {@link Options} object.\n *\n * Example:\n *\n * ```ts\n * {\n * port: number;\n *\n * numWorkers: number;\n *\n * // The \"log\" group\n * log: {\n * level: 'debug' | 'info' | 'warn' | 'error';\n * format: 'text' | 'json'\n * };\n * ...\n * }\n * ```\n */\nexport type Config<O extends Options> = {\n [P in keyof O as O[P] extends Required | Group\n ? P\n : never]: O[P] extends Required\n ? ValueOf<O[P]>\n : O[P] extends Group\n ? ConfigGroup<O[P]>\n : never;\n} & {\n // Values for optional options are in optional fields.\n [P in keyof O as O[P] extends Optional ? P : never]?: O[P] extends Optional\n ? ValueOf<O[P]>\n : never;\n};\n\n/**\n * Creates a defu instance that overrides arrays instead of merging them.\n */\nconst defu = createDefu((obj, key, value) => {\n if (!Array.isArray(value)) return;\n\n obj[key] = value;\n return true;\n});\n\n/**\n * Converts an Options instance into its corresponding {@link Config} schema.\n */\nfunction configSchema<T extends Options>(\n options: T,\n envNamePrefix: string,\n): v.Type<Config<T>> {\n function makeObjectType(options: Options | Group, group?: string) {\n return v.object(\n Object.fromEntries(\n Object.entries(options).map(\n ([name, value]): [string, OptionType | v.Type] => {\n const addErrorMessage = (t: OptionType) => {\n const {required} = getRequiredOrDefault(t);\n if (required) {\n // Adds an error message for required options that includes the\n // actual name of the option.\n const optionName = toSnakeCase(\n `${envNamePrefix}${group ? group + '_' : ''}${name}`,\n ).toUpperCase();\n return (t as v.Type<string>)\n .optional()\n .assert(\n val => val !== undefined,\n `Missing required option ${optionName}`,\n );\n }\n return t;\n };\n // OptionType\n if (v.instanceOfAbstractType(value)) {\n return [name, addErrorMessage(value)];\n }\n // WrappedOptionType\n const {type} = value;\n if (v.instanceOfAbstractType(type)) {\n return [name, addErrorMessage(type)];\n }\n // OptionGroup\n return [name, makeObjectType(value as Group, name)];\n },\n ),\n ),\n );\n }\n return makeObjectType(options) as v.Type<Config<T>>;\n}\n\n/**\n * Converts an Options instance into an \"env schema\", which is an object with\n * ENV names as its keys, mapped to optional or required string values\n * (corresponding to the optionality of the corresponding options).\n *\n * This is used as a format for encoding options for a multi-tenant version\n * of an app, with an envSchema for each tenant.\n */\nexport function envSchema<T extends Options>(options: T, envNamePrefix = '') {\n const fields: [string, v.Type<string> | v.Optional<string>][] = [];\n\n function addField(name: string, type: OptionType, group?: string) {\n const flag = group ? `${group}_${name}` : name;\n const env = toSnakeCase(`${envNamePrefix}${flag}`).toUpperCase();\n\n const {required} = getRequiredOrDefault(type);\n fields.push([env, required ? v.string() : v.string().optional()]);\n }\n\n function addFields(o: Options | Group, group?: string) {\n Object.entries(o).forEach(([name, value]) => {\n // OptionType\n if (v.instanceOfAbstractType(value)) {\n addField(name, value, group);\n return;\n }\n // WrappedOptionType\n const {type} = value;\n if (v.instanceOfAbstractType(type)) {\n addField(name, type, group);\n return;\n }\n // OptionGroup\n addFields(value as Group, name);\n });\n }\n\n addFields(options);\n\n return v.object(Object.fromEntries(fields));\n}\n\n// type TerminalType is not exported from badrap/valita\ntype TerminalType = Parameters<\n Parameters<v.Type<unknown>['toTerminals']>[0]\n>[0];\n\nfunction getRequiredOrDefault(type: OptionType) {\n const defaultResult = v.testOptional<Value>(undefined, type);\n return {\n required: !defaultResult.ok,\n defaultValue: defaultResult.ok ? defaultResult.value : undefined,\n };\n}\n\nexport type ParseOptions = {\n /** Defaults to process.argv.slice(2) */\n argv?: string[];\n\n envNamePrefix?: string;\n\n description?: {header: string; content: string}[];\n\n /** Defaults to `false` */\n allowUnknown?: boolean;\n\n /** Defaults to `false` */\n allowPartial?: boolean;\n\n /** Defaults to `process.env`. */\n env?: NodeJS.ProcessEnv;\n\n /** Defaults to `true`. */\n emitDeprecationWarnings?: boolean;\n\n /** Defaults to `true`. When false, excludes default values from both config and env return values. */\n includeDefaults?: boolean;\n\n /** Defaults to `console` */\n logger?: OptionalLogger;\n\n /** Defaults to `process.exit` */\n exit?: (code?: number | string | null) => never;\n};\n\nexport function parseOptions<T extends Options>(\n appOptions: T,\n opts: ParseOptions = {},\n): Config<T> {\n return parseOptionsAdvanced(appOptions, opts).config;\n}\n\nexport function parseOptionsAdvanced<T extends Options>(\n appOptions: T,\n opts: ParseOptions = {},\n): {config: Config<T>; env: Record<string, string>; unknown?: string[]} {\n const {\n argv = process.argv.slice(2),\n envNamePrefix = '',\n description = [],\n allowUnknown = false,\n allowPartial = false,\n env: processEnv = process.env,\n emitDeprecationWarnings = true,\n includeDefaults = true,\n logger = console,\n exit = process.exit,\n } = opts;\n // The main logic for converting a valita Type spec to an Option (i.e. flag) spec.\n function addOption(field: string, option: WrappedOptionType, group?: string) {\n const {type, desc = [], deprecated, alias, hidden} = option;\n\n // The group name is prepended to the flag name.\n const flag = group ? toKebabCase(`${group}-${field}`) : toKebabCase(field);\n\n const {required, defaultValue} = getRequiredOrDefault(type);\n let multiple = type.name === 'array';\n const literals = new Set<string>();\n const terminalTypes = new Set<string>();\n\n type.toTerminals(getTerminalTypes);\n\n function getTerminalTypes(t: TerminalType) {\n switch (t.name) {\n case 'undefined':\n case 'optional':\n break;\n case 'array': {\n multiple = true;\n t.prefix.forEach(t => t.toTerminals(getTerminalTypes));\n t.rest?.toTerminals(getTerminalTypes);\n t.suffix.forEach(t => t.toTerminals(getTerminalTypes));\n break;\n }\n case 'literal':\n literals.add(String(t.value));\n terminalTypes.add(typeof t.value);\n break;\n default:\n terminalTypes.add(t.name);\n break;\n }\n }\n const env = toSnakeCase(`${envNamePrefix}${flag}`).toUpperCase();\n if (terminalTypes.size > 1) {\n throw new TypeError(`${env} has mixed types ${[...terminalTypes]}`);\n }\n assert(terminalTypes.size === 1);\n const terminalType = [...terminalTypes][0];\n\n if (processEnv[env]) {\n if (multiple) {\n // Technically not water-tight; assumes values for the string[] flag don't contain commas.\n envArgv.push(`--${flag}`, ...processEnv[env].split(','));\n } else {\n envArgv.push(`--${flag}`, processEnv[env]);\n }\n }\n names.set(flag, {field, env});\n\n const spec = [\n (required\n ? '{italic required}'\n : defaultValue !== undefined\n ? `default: ${JSON.stringify(defaultValue)}`\n : 'optional') + '\\n',\n ];\n if (desc) {\n spec.push(...desc);\n }\n\n const typeLabel = [\n literals.size\n ? String([...literals].map(l => `{underline ${l}}`))\n : multiple\n ? `{underline ${terminalType}[]}`\n : `{underline ${terminalType}}`,\n ` ${env} env`,\n ];\n\n const opt = {\n name: flag,\n alias,\n type: valueParser(\n env,\n terminalType,\n logger,\n emitDeprecationWarnings ? deprecated : undefined,\n ),\n multiple,\n group,\n description: spec.join('\\n') + '\\n',\n typeLabel: typeLabel.join('\\n') + '\\n',\n hidden: hidden === undefined ? deprecated !== undefined : hidden,\n };\n optsWithoutDefaults.push(opt);\n optsWithDefaults.push({...opt, defaultValue});\n }\n\n const names = new Map<string, {field: string; env: string}>();\n const optsWithDefaults: DescribedOptionDefinition[] = [];\n const optsWithoutDefaults: DescribedOptionDefinition[] = [];\n const envArgv: string[] = [];\n\n try {\n for (const [name, val] of Object.entries(appOptions)) {\n const {type} = val as {type: unknown};\n if (v.instanceOfAbstractType(val)) {\n addOption(name, {type: val});\n } else if (v.instanceOfAbstractType(type)) {\n addOption(name, val as WrappedOptionType);\n } else {\n const group = name;\n for (const [name, option] of Object.entries(val as Group)) {\n const wrapped = v.instanceOfAbstractType(option)\n ? {type: option}\n : option;\n addOption(name, wrapped, group);\n }\n }\n }\n\n const [defaults, env1, unknown] = parseArgs(optsWithDefaults, argv, names);\n const [fromEnv, env2] = parseArgs(optsWithoutDefaults, envArgv, names);\n const [withoutDefaults, env3] = parseArgs(optsWithoutDefaults, argv, names);\n\n switch (unknown?.[0]) {\n case undefined:\n break;\n case '--help':\n case '-h':\n showUsage(optsWithDefaults, description, logger);\n exit(0);\n break;\n default:\n if (!allowUnknown) {\n logger.error?.('Invalid arguments:', unknown);\n showUsage(optsWithDefaults, description, logger);\n exit(0);\n }\n break;\n }\n\n const parsedArgs = includeDefaults\n ? defu(withoutDefaults, fromEnv, defaults)\n : defu(withoutDefaults, fromEnv);\n const env = includeDefaults\n ? {...env1, ...env2, ...env3}\n : {...env2, ...env3};\n\n let schema = configSchema(appOptions, envNamePrefix);\n if (allowPartial || !includeDefaults) {\n // TODO: Type configSchema() to return a v.ObjectType<...>\n schema = v.deepPartial(schema as v.ObjectType) as v.Type<Config<T>>;\n }\n return {\n config: v.parse(parsedArgs, schema),\n env,\n ...(unknown ? {unknown} : {}),\n };\n } catch (e) {\n logger.error?.(String(e));\n showUsage(optsWithDefaults, description, logger);\n throw e;\n }\n}\n\nfunction valueParser(\n optionName: string,\n typeName: string,\n logger: OptionalLogger,\n deprecated: string[] | undefined,\n) {\n return (input: string) => {\n if (deprecated) {\n logger.warn?.(\n template(\n `\\n${optionName} is deprecated:\\n` + deprecated.join('\\n') + '\\n',\n ),\n );\n }\n switch (typeName) {\n case 'string':\n return input;\n case 'boolean':\n return parseBoolean(optionName, input);\n case 'number': {\n const val = Number(input);\n if (Number.isNaN(val)) {\n throw new TypeError(`Invalid input for ${optionName}: \"${input}\"`);\n }\n return val;\n }\n default:\n // Should be impossible given the constraints of `Option`\n throw new TypeError(\n `${optionName} option has unsupported type ${typeName}`,\n );\n }\n };\n}\n\nfunction parseArgs(\n optionDefs: DescribedOptionDefinition[],\n argv: string[],\n names: Map<string, {field: string; env: string}>,\n) {\n function normalizeFlagValue(value: unknown) {\n // A --flag without value is parsed by commandLineArgs() to `null`,\n // but this is a common convention to set a boolean flag to true.\n return value === null ? true : value;\n }\n\n const {\n _all,\n _none: ungrouped,\n _unknown: unknown,\n ...config\n } = commandLineArgs(optionDefs, {\n argv,\n partial: true,\n });\n\n // oxlint-disable-next-line @typescript-eslint/no-explicit-any\n const result: Record<string, any> = {};\n const envObj: Record<string, string> = {};\n\n function addFlag(flagName: string, value: unknown, group?: string) {\n const {field, env} = must(names.get(flagName));\n const normalized = normalizeFlagValue(value);\n if (group) {\n result[group][field] = normalized;\n } else {\n result[field] = normalized;\n }\n envObj[env] = String(normalized);\n }\n\n for (const [flagName, value] of Object.entries(ungrouped ?? {})) {\n addFlag(flagName, value);\n }\n\n // Then handle (potentially) grouped flags\n for (const [name, value] of Object.entries(config)) {\n if (typeof value !== 'object' || value === null || Array.isArray(value)) {\n addFlag(name, value); // Flag, not a group\n } else {\n const group = name;\n result[group] = {};\n for (const [flagName, flagValue] of Object.entries(value)) {\n addFlag(flagName, flagValue, group);\n }\n }\n }\n\n return [result, envObj, unknown] as const;\n}\n\nexport function parseBoolean(optionName: string, input: string) {\n const bool = input.toLowerCase();\n if (['true', '1'].includes(bool)) {\n return true;\n } else if (['false', '0'].includes(bool)) {\n return false;\n }\n throw new TypeError(`Invalid input for ${optionName}: \"${input}\"`);\n}\n\nfunction showUsage(\n optionList: DescribedOptionDefinition[],\n description: {header: string; content: string}[] = [],\n logger: OptionalLogger = console,\n) {\n const hide: string[] = [];\n let leftWidth = 35;\n let rightWidth = 70;\n optionList.forEach(({name, typeLabel, description, hidden}) => {\n if (hidden) {\n hide.push(name);\n }\n const text = template(`${name} ${typeLabel ?? ''}`);\n const lines = stripAnsi(text).split('\\n');\n for (const l of lines) {\n leftWidth = Math.max(leftWidth, l.length + 2);\n }\n const desc = stripAnsi(template(description ?? '')).split('\\n');\n for (const l of desc) {\n rightWidth = Math.max(rightWidth, l.length + 2);\n }\n });\n\n const sections: Section[] = [\n {\n optionList,\n reverseNameOrder: true, // Display --flag-name before -alias\n hide,\n tableOptions: {\n columns: [\n {name: 'option', width: leftWidth},\n {name: 'description', width: rightWidth},\n ],\n noTrim: true,\n },\n },\n ];\n\n if (description) {\n sections.unshift(...description);\n }\n\n logger.info?.(commandLineUsage(sections));\n}\n\ntype DescribedOptionDefinition = OptionDefinition & {\n // Additional fields recognized by command-line-usage\n description?: string;\n typeLabel?: string | undefined;\n hidden?: boolean | undefined;\n};\n"],"names":["options","v.object","v.instanceOfAbstractType","v.testOptional","t","name","v.deepPartial","v.parse","description","stripAnsi"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"options.js","sources":["../../../../shared/src/options.ts"],"sourcesContent":["import type {OptionalLogger} from '@rocicorp/logger';\nimport {template} from 'chalk-template';\nimport type {OptionDefinition} from 'command-line-args';\nimport commandLineArgs from 'command-line-args';\nimport commandLineUsage, {type Section} from 'command-line-usage';\nimport {createDefu} from 'defu';\nimport {toKebabCase, toSnakeCase} from 'kasi';\nimport {stripVTControlCharacters as stripAnsi} from 'node:util';\nimport {assert} from './asserts.ts';\nimport {must} from './must.ts';\nimport type {\n Config,\n Group,\n Option,\n Options,\n WrappedOptionType,\n} from './options-types.ts';\nimport * as v from './valita.ts';\n\nexport type {Config, Group, Option, Options, WrappedOptionType};\n\ntype Primitive = number | string | boolean;\ntype Value = Primitive | Array<Primitive>;\n\ntype RequiredOptionType =\n | v.Type<string>\n | v.Type<number>\n | v.Type<boolean>\n | v.Type<string[]>\n | v.Type<number[]>\n | v.Type<boolean[]>;\n\ntype OptionalOptionType =\n | v.Optional<string>\n | v.Optional<number>\n | v.Optional<boolean>\n | v.Optional<string[]>\n | v.Optional<number[]>\n | v.Optional<boolean[]>;\n\ntype OptionType = RequiredOptionType | OptionalOptionType;\n\n/**\n * Creates a defu instance that overrides arrays instead of merging them.\n */\nconst defu = createDefu((obj, key, value) => {\n if (!Array.isArray(value)) return;\n\n obj[key] = value;\n return true;\n});\n\n/**\n * Converts an Options instance into its corresponding {@link Config} schema.\n */\nfunction configSchema<T extends Options>(\n options: T,\n envNamePrefix: string,\n): v.Type<Config<T>> {\n function makeObjectType(options: Options | Group, group?: string) {\n return v.object(\n Object.fromEntries(\n Object.entries(options).map(\n ([name, value]): [string, OptionType | v.Type] => {\n const addErrorMessage = (t: OptionType) => {\n const {required} = getRequiredOrDefault(t);\n if (required) {\n // Adds an error message for required options that includes the\n // actual name of the option.\n const optionName = toSnakeCase(\n `${envNamePrefix}${group ? group + '_' : ''}${name}`,\n ).toUpperCase();\n return (t as v.Type<string>)\n .optional()\n .assert(\n val => val !== undefined,\n `Missing required option ${optionName}`,\n );\n }\n return t;\n };\n // OptionType\n if (v.instanceOfAbstractType(value)) {\n return [name, addErrorMessage(value)];\n }\n // WrappedOptionType\n const {type} = value;\n if (v.instanceOfAbstractType(type)) {\n return [name, addErrorMessage(type)];\n }\n // OptionGroup\n return [name, makeObjectType(value as Group, name)];\n },\n ),\n ),\n );\n }\n return makeObjectType(options) as v.Type<Config<T>>;\n}\n\n/**\n * Converts an Options instance into an \"env schema\", which is an object with\n * ENV names as its keys, mapped to optional or required string values\n * (corresponding to the optionality of the corresponding options).\n *\n * This is used as a format for encoding options for a multi-tenant version\n * of an app, with an envSchema for each tenant.\n */\nexport function envSchema<T extends Options>(options: T, envNamePrefix = '') {\n const fields: [string, v.Type<string> | v.Optional<string>][] = [];\n\n function addField(name: string, type: OptionType, group?: string) {\n const flag = group ? `${group}_${name}` : name;\n const env = toSnakeCase(`${envNamePrefix}${flag}`).toUpperCase();\n\n const {required} = getRequiredOrDefault(type);\n fields.push([env, required ? v.string() : v.string().optional()]);\n }\n\n function addFields(o: Options | Group, group?: string) {\n Object.entries(o).forEach(([name, value]) => {\n // OptionType\n if (v.instanceOfAbstractType(value)) {\n addField(name, value, group);\n return;\n }\n // WrappedOptionType\n const {type} = value;\n if (v.instanceOfAbstractType(type)) {\n addField(name, type, group);\n return;\n }\n // OptionGroup\n addFields(value as Group, name);\n });\n }\n\n addFields(options);\n\n return v.object(Object.fromEntries(fields));\n}\n\n// type TerminalType is not exported from badrap/valita\ntype TerminalType = Parameters<\n Parameters<v.Type<unknown>['toTerminals']>[0]\n>[0];\n\nfunction getRequiredOrDefault(type: OptionType) {\n const defaultResult = v.testOptional<Value>(undefined, type);\n return {\n required: !defaultResult.ok,\n defaultValue: defaultResult.ok ? defaultResult.value : undefined,\n };\n}\n\nexport type ParseOptions = {\n /** Defaults to process.argv.slice(2) */\n argv?: string[];\n\n envNamePrefix?: string;\n\n description?: {header: string; content: string}[];\n\n /** Defaults to `false` */\n allowUnknown?: boolean;\n\n /** Defaults to `false` */\n allowPartial?: boolean;\n\n /** Defaults to `process.env`. */\n env?: NodeJS.ProcessEnv;\n\n /** Defaults to `true`. */\n emitDeprecationWarnings?: boolean;\n\n /** Defaults to `true`. When false, excludes default values from both config and env return values. */\n includeDefaults?: boolean;\n\n /** Defaults to `console` */\n logger?: OptionalLogger;\n\n /** Defaults to `process.exit` */\n exit?: (code?: number | string | null) => never;\n};\n\nexport function parseOptions<T extends Options>(\n appOptions: T,\n opts: ParseOptions = {},\n): Config<T> {\n return parseOptionsAdvanced(appOptions, opts).config;\n}\n\nexport function parseOptionsAdvanced<T extends Options>(\n appOptions: T,\n opts: ParseOptions = {},\n): {config: Config<T>; env: Record<string, string>; unknown?: string[]} {\n const {\n argv = process.argv.slice(2),\n envNamePrefix = '',\n description = [],\n allowUnknown = false,\n allowPartial = false,\n env: processEnv = process.env,\n emitDeprecationWarnings = true,\n includeDefaults = true,\n logger = console,\n exit = process.exit,\n } = opts;\n // The main logic for converting a valita Type spec to an Option (i.e. flag) spec.\n function addOption(field: string, option: WrappedOptionType, group?: string) {\n const {type, desc = [], deprecated, alias, hidden} = option;\n\n // The group name is prepended to the flag name.\n const flag = group ? toKebabCase(`${group}-${field}`) : toKebabCase(field);\n\n const {required, defaultValue} = getRequiredOrDefault(type);\n let multiple = type.name === 'array';\n const literals = new Set<string>();\n const terminalTypes = new Set<string>();\n\n type.toTerminals(getTerminalTypes);\n\n function getTerminalTypes(t: TerminalType) {\n switch (t.name) {\n case 'undefined':\n case 'optional':\n break;\n case 'array': {\n multiple = true;\n t.prefix.forEach(t => t.toTerminals(getTerminalTypes));\n t.rest?.toTerminals(getTerminalTypes);\n t.suffix.forEach(t => t.toTerminals(getTerminalTypes));\n break;\n }\n case 'literal':\n literals.add(String(t.value));\n terminalTypes.add(typeof t.value);\n break;\n default:\n terminalTypes.add(t.name);\n break;\n }\n }\n const env = toSnakeCase(`${envNamePrefix}${flag}`).toUpperCase();\n if (terminalTypes.size > 1) {\n throw new TypeError(`${env} has mixed types ${[...terminalTypes]}`);\n }\n assert(terminalTypes.size === 1);\n const terminalType = [...terminalTypes][0];\n\n if (processEnv[env]) {\n if (multiple) {\n // Technically not water-tight; assumes values for the string[] flag don't contain commas.\n envArgv.push(`--${flag}`, ...processEnv[env].split(','));\n } else {\n envArgv.push(`--${flag}`, processEnv[env]);\n }\n }\n names.set(flag, {field, env});\n\n const spec = [\n (required\n ? '{italic required}'\n : defaultValue !== undefined\n ? `default: ${JSON.stringify(defaultValue)}`\n : 'optional') + '\\n',\n ];\n if (desc) {\n spec.push(...desc);\n }\n\n const typeLabel = [\n literals.size\n ? String([...literals].map(l => `{underline ${l}}`))\n : multiple\n ? `{underline ${terminalType}[]}`\n : `{underline ${terminalType}}`,\n ` ${env} env`,\n ];\n\n const opt = {\n name: flag,\n alias,\n type: valueParser(\n env,\n terminalType,\n logger,\n emitDeprecationWarnings ? deprecated : undefined,\n ),\n multiple,\n group,\n description: spec.join('\\n') + '\\n',\n typeLabel: typeLabel.join('\\n') + '\\n',\n hidden: hidden === undefined ? deprecated !== undefined : hidden,\n };\n optsWithoutDefaults.push(opt);\n optsWithDefaults.push({...opt, defaultValue});\n }\n\n const names = new Map<string, {field: string; env: string}>();\n const optsWithDefaults: DescribedOptionDefinition[] = [];\n const optsWithoutDefaults: DescribedOptionDefinition[] = [];\n const envArgv: string[] = [];\n\n try {\n for (const [name, val] of Object.entries(appOptions)) {\n const {type} = val as {type: unknown};\n if (v.instanceOfAbstractType(val)) {\n addOption(name, {type: val});\n } else if (v.instanceOfAbstractType(type)) {\n addOption(name, val as WrappedOptionType);\n } else {\n const group = name;\n for (const [name, option] of Object.entries(val as Group)) {\n const wrapped = v.instanceOfAbstractType(option)\n ? {type: option}\n : option;\n addOption(name, wrapped, group);\n }\n }\n }\n\n const [defaults, env1, unknown] = parseArgs(optsWithDefaults, argv, names);\n const [fromEnv, env2] = parseArgs(optsWithoutDefaults, envArgv, names);\n const [withoutDefaults, env3] = parseArgs(optsWithoutDefaults, argv, names);\n\n switch (unknown?.[0]) {\n case undefined:\n break;\n case '--help':\n case '-h':\n showUsage(optsWithDefaults, description, logger);\n exit(0);\n break;\n default:\n if (!allowUnknown) {\n logger.error?.('Invalid arguments:', unknown);\n showUsage(optsWithDefaults, description, logger);\n exit(0);\n }\n break;\n }\n\n const parsedArgs = includeDefaults\n ? defu(withoutDefaults, fromEnv, defaults)\n : defu(withoutDefaults, fromEnv);\n const env = includeDefaults\n ? {...env1, ...env2, ...env3}\n : {...env2, ...env3};\n\n let schema = configSchema(appOptions, envNamePrefix);\n if (allowPartial || !includeDefaults) {\n // TODO: Type configSchema() to return a v.ObjectType<...>\n schema = v.deepPartial(schema as v.ObjectType) as v.Type<Config<T>>;\n }\n return {\n config: v.parse(parsedArgs, schema),\n env,\n ...(unknown ? {unknown} : {}),\n };\n } catch (e) {\n logger.error?.(String(e));\n showUsage(optsWithDefaults, description, logger);\n throw e;\n }\n}\n\nfunction valueParser(\n optionName: string,\n typeName: string,\n logger: OptionalLogger,\n deprecated: string[] | undefined,\n) {\n return (input: string) => {\n if (deprecated) {\n logger.warn?.(\n template(\n `\\n${optionName} is deprecated:\\n` + deprecated.join('\\n') + '\\n',\n ),\n );\n }\n switch (typeName) {\n case 'string':\n return input;\n case 'boolean':\n return parseBoolean(optionName, input);\n case 'number': {\n const val = Number(input);\n if (Number.isNaN(val)) {\n throw new TypeError(`Invalid input for ${optionName}: \"${input}\"`);\n }\n return val;\n }\n default:\n // Should be impossible given the constraints of `Option`\n throw new TypeError(\n `${optionName} option has unsupported type ${typeName}`,\n );\n }\n };\n}\n\nfunction parseArgs(\n optionDefs: DescribedOptionDefinition[],\n argv: string[],\n names: Map<string, {field: string; env: string}>,\n) {\n function normalizeFlagValue(value: unknown) {\n // A --flag without value is parsed by commandLineArgs() to `null`,\n // but this is a common convention to set a boolean flag to true.\n return value === null ? true : value;\n }\n\n const {\n _all,\n _none: ungrouped,\n _unknown: unknown,\n ...config\n } = commandLineArgs(optionDefs, {\n argv,\n partial: true,\n });\n\n // oxlint-disable-next-line @typescript-eslint/no-explicit-any\n const result: Record<string, any> = {};\n const envObj: Record<string, string> = {};\n\n function addFlag(flagName: string, value: unknown, group?: string) {\n const {field, env} = must(names.get(flagName));\n const normalized = normalizeFlagValue(value);\n if (group) {\n result[group][field] = normalized;\n } else {\n result[field] = normalized;\n }\n envObj[env] = String(normalized);\n }\n\n for (const [flagName, value] of Object.entries(ungrouped ?? {})) {\n addFlag(flagName, value);\n }\n\n // Then handle (potentially) grouped flags\n for (const [name, value] of Object.entries(config)) {\n if (typeof value !== 'object' || value === null || Array.isArray(value)) {\n addFlag(name, value); // Flag, not a group\n } else {\n const group = name;\n result[group] = {};\n for (const [flagName, flagValue] of Object.entries(value)) {\n addFlag(flagName, flagValue, group);\n }\n }\n }\n\n return [result, envObj, unknown] as const;\n}\n\nexport function parseBoolean(optionName: string, input: string) {\n const bool = input.toLowerCase();\n if (['true', '1'].includes(bool)) {\n return true;\n } else if (['false', '0'].includes(bool)) {\n return false;\n }\n throw new TypeError(`Invalid input for ${optionName}: \"${input}\"`);\n}\n\nfunction showUsage(\n optionList: DescribedOptionDefinition[],\n description: {header: string; content: string}[] = [],\n logger: OptionalLogger = console,\n) {\n const hide: string[] = [];\n let leftWidth = 35;\n let rightWidth = 70;\n optionList.forEach(({name, typeLabel, description, hidden}) => {\n if (hidden) {\n hide.push(name);\n }\n const text = template(`${name} ${typeLabel ?? ''}`);\n const lines = stripAnsi(text).split('\\n');\n for (const l of lines) {\n leftWidth = Math.max(leftWidth, l.length + 2);\n }\n const desc = stripAnsi(template(description ?? '')).split('\\n');\n for (const l of desc) {\n rightWidth = Math.max(rightWidth, l.length + 2);\n }\n });\n\n const sections: Section[] = [\n {\n optionList,\n reverseNameOrder: true, // Display --flag-name before -alias\n hide,\n tableOptions: {\n columns: [\n {name: 'option', width: leftWidth},\n {name: 'description', width: rightWidth},\n ],\n noTrim: true,\n },\n },\n ];\n\n if (description) {\n sections.unshift(...description);\n }\n\n logger.info?.(commandLineUsage(sections));\n}\n\ntype DescribedOptionDefinition = OptionDefinition & {\n // Additional fields recognized by command-line-usage\n description?: string;\n typeLabel?: string | undefined;\n hidden?: boolean | undefined;\n};\n"],"names":["options","v.object","v.instanceOfAbstractType","v.testOptional","t","name","v.deepPartial","v.parse","description","stripAnsi"],"mappings":";;;;;;;;;;AA6CA,MAAM,OAAO,WAAW,CAAC,KAAK,KAAK,UAAU;AAC3C,MAAI,CAAC,MAAM,QAAQ,KAAK,EAAG;AAE3B,MAAI,GAAG,IAAI;AACX,SAAO;AACT,CAAC;AAKD,SAAS,aACP,SACA,eACmB;AACnB,WAAS,eAAeA,UAA0B,OAAgB;AAChE,WAAOC;AAAAA,MACL,OAAO;AAAA,QACL,OAAO,QAAQD,QAAO,EAAE;AAAA,UACtB,CAAC,CAAC,MAAM,KAAK,MAAqC;AAChD,kBAAM,kBAAkB,CAAC,MAAkB;AACzC,oBAAM,EAAC,SAAA,IAAY,qBAAqB,CAAC;AACzC,kBAAI,UAAU;AAGZ,sBAAM,aAAa;AAAA,kBACjB,GAAG,aAAa,GAAG,QAAQ,QAAQ,MAAM,EAAE,GAAG,IAAI;AAAA,gBAAA,EAClD,YAAA;AACF,uBAAQ,EACL,WACA;AAAA,kBACC,SAAO,QAAQ;AAAA,kBACf,2BAA2B,UAAU;AAAA,gBAAA;AAAA,cAE3C;AACA,qBAAO;AAAA,YACT;AAEA,gBAAIE,uBAAyB,KAAK,GAAG;AACnC,qBAAO,CAAC,MAAM,gBAAgB,KAAK,CAAC;AAAA,YACtC;AAEA,kBAAM,EAAC,SAAQ;AACf,gBAAIA,uBAAyB,IAAI,GAAG;AAClC,qBAAO,CAAC,MAAM,gBAAgB,IAAI,CAAC;AAAA,YACrC;AAEA,mBAAO,CAAC,MAAM,eAAe,OAAgB,IAAI,CAAC;AAAA,UACpD;AAAA,QAAA;AAAA,MACF;AAAA,IACF;AAAA,EAEJ;AACA,SAAO,eAAe,OAAO;AAC/B;AAiDA,SAAS,qBAAqB,MAAkB;AAC9C,QAAM,gBAAgBC,aAAsB,QAAW,IAAI;AAC3D,SAAO;AAAA,IACL,UAAU,CAAC,cAAc;AAAA,IACzB,cAAc,cAAc,KAAK,cAAc,QAAQ;AAAA,EAAA;AAE3D;AAgCO,SAAS,aACd,YACA,OAAqB,IACV;AACX,SAAO,qBAAqB,YAAY,IAAI,EAAE;AAChD;AAEO,SAAS,qBACd,YACA,OAAqB,IACiD;AACtE,QAAM;AAAA,IACJ,OAAO,QAAQ,KAAK,MAAM,CAAC;AAAA,IAC3B,gBAAgB;AAAA,IAChB,cAAc,CAAA;AAAA,IACd,eAAe;AAAA,IACf,eAAe;AAAA,IACf,KAAK,aAAa,QAAQ;AAAA,IAC1B,0BAA0B;AAAA,IAC1B,kBAAkB;AAAA,IAClB,SAAS;AAAA,IACT,OAAO,QAAQ;AAAA,EAAA,IACb;AAEJ,WAAS,UAAU,OAAe,QAA2B,OAAgB;AAC3E,UAAM,EAAC,MAAM,OAAO,CAAA,GAAI,YAAY,OAAO,WAAU;AAGrD,UAAM,OAAO,QAAQ,YAAY,GAAG,KAAK,IAAI,KAAK,EAAE,IAAI,YAAY,KAAK;AAEzE,UAAM,EAAC,UAAU,iBAAgB,qBAAqB,IAAI;AAC1D,QAAI,WAAW,KAAK,SAAS;AAC7B,UAAM,+BAAe,IAAA;AACrB,UAAM,oCAAoB,IAAA;AAE1B,SAAK,YAAY,gBAAgB;AAEjC,aAAS,iBAAiB,GAAiB;AACzC,cAAQ,EAAE,MAAA;AAAA,QACR,KAAK;AAAA,QACL,KAAK;AACH;AAAA,QACF,KAAK,SAAS;AACZ,qBAAW;AACX,YAAE,OAAO,QAAQ,CAAAC,OAAKA,GAAE,YAAY,gBAAgB,CAAC;AACrD,YAAE,MAAM,YAAY,gBAAgB;AACpC,YAAE,OAAO,QAAQ,CAAAA,OAAKA,GAAE,YAAY,gBAAgB,CAAC;AACrD;AAAA,QACF;AAAA,QACA,KAAK;AACH,mBAAS,IAAI,OAAO,EAAE,KAAK,CAAC;AAC5B,wBAAc,IAAI,OAAO,EAAE,KAAK;AAChC;AAAA,QACF;AACE,wBAAc,IAAI,EAAE,IAAI;AACxB;AAAA,MAAA;AAAA,IAEN;AACA,UAAM,MAAM,YAAY,GAAG,aAAa,GAAG,IAAI,EAAE,EAAE,YAAA;AACnD,QAAI,cAAc,OAAO,GAAG;AAC1B,YAAM,IAAI,UAAU,GAAG,GAAG,oBAAoB,CAAC,GAAG,aAAa,CAAC,EAAE;AAAA,IACpE;AACA,WAAO,cAAc,SAAS,CAAC;AAC/B,UAAM,eAAe,CAAC,GAAG,aAAa,EAAE,CAAC;AAEzC,QAAI,WAAW,GAAG,GAAG;AACnB,UAAI,UAAU;AAEZ,gBAAQ,KAAK,KAAK,IAAI,IAAI,GAAG,WAAW,GAAG,EAAE,MAAM,GAAG,CAAC;AAAA,MACzD,OAAO;AACL,gBAAQ,KAAK,KAAK,IAAI,IAAI,WAAW,GAAG,CAAC;AAAA,MAC3C;AAAA,IACF;AACA,UAAM,IAAI,MAAM,EAAC,OAAO,KAAI;AAE5B,UAAM,OAAO;AAAA,OACV,WACG,sBACA,iBAAiB,SACf,YAAY,KAAK,UAAU,YAAY,CAAC,KACxC,cAAc;AAAA,IAAA;AAEtB,QAAI,MAAM;AACR,WAAK,KAAK,GAAG,IAAI;AAAA,IACnB;AAEA,UAAM,YAAY;AAAA,MAChB,SAAS,OACL,OAAO,CAAC,GAAG,QAAQ,EAAE,IAAI,CAAA,MAAK,cAAc,CAAC,GAAG,CAAC,IACjD,WACE,cAAc,YAAY,QAC1B,cAAc,YAAY;AAAA,MAChC,KAAK,GAAG;AAAA,IAAA;AAGV,UAAM,MAAM;AAAA,MACV,MAAM;AAAA,MACN;AAAA,MACA,MAAM;AAAA,QACJ;AAAA,QACA;AAAA,QACA;AAAA,QACA,0BAA0B,aAAa;AAAA,MAAA;AAAA,MAEzC;AAAA,MACA;AAAA,MACA,aAAa,KAAK,KAAK,IAAI,IAAI;AAAA,MAC/B,WAAW,UAAU,KAAK,IAAI,IAAI;AAAA,MAClC,QAAQ,WAAW,SAAY,eAAe,SAAY;AAAA,IAAA;AAE5D,wBAAoB,KAAK,GAAG;AAC5B,qBAAiB,KAAK,EAAC,GAAG,KAAK,cAAa;AAAA,EAC9C;AAEA,QAAM,4BAAY,IAAA;AAClB,QAAM,mBAAgD,CAAA;AACtD,QAAM,sBAAmD,CAAA;AACzD,QAAM,UAAoB,CAAA;AAE1B,MAAI;AACF,eAAW,CAAC,MAAM,GAAG,KAAK,OAAO,QAAQ,UAAU,GAAG;AACpD,YAAM,EAAC,SAAQ;AACf,UAAIF,uBAAyB,GAAG,GAAG;AACjC,kBAAU,MAAM,EAAC,MAAM,IAAA,CAAI;AAAA,MAC7B,WAAWA,uBAAyB,IAAI,GAAG;AACzC,kBAAU,MAAM,GAAwB;AAAA,MAC1C,OAAO;AACL,cAAM,QAAQ;AACd,mBAAW,CAACG,OAAM,MAAM,KAAK,OAAO,QAAQ,GAAY,GAAG;AACzD,gBAAM,UAAUH,uBAAyB,MAAM,IAC3C,EAAC,MAAM,WACP;AACJ,oBAAUG,OAAM,SAAS,KAAK;AAAA,QAChC;AAAA,MACF;AAAA,IACF;AAEA,UAAM,CAAC,UAAU,MAAM,OAAO,IAAI,UAAU,kBAAkB,MAAM,KAAK;AACzE,UAAM,CAAC,SAAS,IAAI,IAAI,UAAU,qBAAqB,SAAS,KAAK;AACrE,UAAM,CAAC,iBAAiB,IAAI,IAAI,UAAU,qBAAqB,MAAM,KAAK;AAE1E,YAAQ,UAAU,CAAC,GAAA;AAAA,MACjB,KAAK;AACH;AAAA,MACF,KAAK;AAAA,MACL,KAAK;AACH,kBAAU,kBAAkB,aAAa,MAAM;AAC/C,aAAK,CAAC;AACN;AAAA,MACF;AACE,YAAI,CAAC,cAAc;AACjB,iBAAO,QAAQ,sBAAsB,OAAO;AAC5C,oBAAU,kBAAkB,aAAa,MAAM;AAC/C,eAAK,CAAC;AAAA,QACR;AACA;AAAA,IAAA;AAGJ,UAAM,aAAa,kBACf,KAAK,iBAAiB,SAAS,QAAQ,IACvC,KAAK,iBAAiB,OAAO;AACjC,UAAM,MAAM,kBACR,EAAC,GAAG,MAAM,GAAG,MAAM,GAAG,SACtB,EAAC,GAAG,MAAM,GAAG,KAAA;AAEjB,QAAI,SAAS,aAAa,YAAY,aAAa;AACnD,QAAI,gBAAgB,CAAC,iBAAiB;AAEpC,eAASC,YAAc,MAAsB;AAAA,IAC/C;AACA,WAAO;AAAA,MACL,QAAQC,MAAQ,YAAY,MAAM;AAAA,MAClC;AAAA,MACA,GAAI,UAAU,EAAC,YAAW,CAAA;AAAA,IAAC;AAAA,EAE/B,SAAS,GAAG;AACV,WAAO,QAAQ,OAAO,CAAC,CAAC;AACxB,cAAU,kBAAkB,aAAa,MAAM;AAC/C,UAAM;AAAA,EACR;AACF;AAEA,SAAS,YACP,YACA,UACA,QACA,YACA;AACA,SAAO,CAAC,UAAkB;AACxB,QAAI,YAAY;AACd,aAAO;AAAA,QACL;AAAA,UACE;AAAA,EAAK,UAAU;AAAA,IAAsB,WAAW,KAAK,IAAI,IAAI;AAAA,QAAA;AAAA,MAC/D;AAAA,IAEJ;AACA,YAAQ,UAAA;AAAA,MACN,KAAK;AACH,eAAO;AAAA,MACT,KAAK;AACH,eAAO,aAAa,YAAY,KAAK;AAAA,MACvC,KAAK,UAAU;AACb,cAAM,MAAM,OAAO,KAAK;AACxB,YAAI,OAAO,MAAM,GAAG,GAAG;AACrB,gBAAM,IAAI,UAAU,qBAAqB,UAAU,MAAM,KAAK,GAAG;AAAA,QACnE;AACA,eAAO;AAAA,MACT;AAAA,MACA;AAEE,cAAM,IAAI;AAAA,UACR,GAAG,UAAU,gCAAgC,QAAQ;AAAA,QAAA;AAAA,IACvD;AAAA,EAEN;AACF;AAEA,SAAS,UACP,YACA,MACA,OACA;AACA,WAAS,mBAAmB,OAAgB;AAG1C,WAAO,UAAU,OAAO,OAAO;AAAA,EACjC;AAEA,QAAM;AAAA,IACJ;AAAA,IACA,OAAO;AAAA,IACP,UAAU;AAAA,IACV,GAAG;AAAA,EAAA,IACD,gBAAgB,YAAY;AAAA,IAC9B;AAAA,IACA,SAAS;AAAA,EAAA,CACV;AAGD,QAAM,SAA8B,CAAA;AACpC,QAAM,SAAiC,CAAA;AAEvC,WAAS,QAAQ,UAAkB,OAAgB,OAAgB;AACjE,UAAM,EAAC,OAAO,IAAA,IAAO,KAAK,MAAM,IAAI,QAAQ,CAAC;AAC7C,UAAM,aAAa,mBAAmB,KAAK;AAC3C,QAAI,OAAO;AACT,aAAO,KAAK,EAAE,KAAK,IAAI;AAAA,IACzB,OAAO;AACL,aAAO,KAAK,IAAI;AAAA,IAClB;AACA,WAAO,GAAG,IAAI,OAAO,UAAU;AAAA,EACjC;AAEA,aAAW,CAAC,UAAU,KAAK,KAAK,OAAO,QAAQ,aAAa,CAAA,CAAE,GAAG;AAC/D,YAAQ,UAAU,KAAK;AAAA,EACzB;AAGA,aAAW,CAAC,MAAM,KAAK,KAAK,OAAO,QAAQ,MAAM,GAAG;AAClD,QAAI,OAAO,UAAU,YAAY,UAAU,QAAQ,MAAM,QAAQ,KAAK,GAAG;AACvE,cAAQ,MAAM,KAAK;AAAA,IACrB,OAAO;AACL,YAAM,QAAQ;AACd,aAAO,KAAK,IAAI,CAAA;AAChB,iBAAW,CAAC,UAAU,SAAS,KAAK,OAAO,QAAQ,KAAK,GAAG;AACzD,gBAAQ,UAAU,WAAW,KAAK;AAAA,MACpC;AAAA,IACF;AAAA,EACF;AAEA,SAAO,CAAC,QAAQ,QAAQ,OAAO;AACjC;AAEO,SAAS,aAAa,YAAoB,OAAe;AAC9D,QAAM,OAAO,MAAM,YAAA;AACnB,MAAI,CAAC,QAAQ,GAAG,EAAE,SAAS,IAAI,GAAG;AAChC,WAAO;AAAA,EACT,WAAW,CAAC,SAAS,GAAG,EAAE,SAAS,IAAI,GAAG;AACxC,WAAO;AAAA,EACT;AACA,QAAM,IAAI,UAAU,qBAAqB,UAAU,MAAM,KAAK,GAAG;AACnE;AAEA,SAAS,UACP,YACA,cAAmD,CAAA,GACnD,SAAyB,SACzB;AACA,QAAM,OAAiB,CAAA;AACvB,MAAI,YAAY;AAChB,MAAI,aAAa;AACjB,aAAW,QAAQ,CAAC,EAAC,MAAM,WAAW,aAAAC,cAAa,aAAY;AAC7D,QAAI,QAAQ;AACV,WAAK,KAAK,IAAI;AAAA,IAChB;AACA,UAAM,OAAO,SAAS,GAAG,IAAI,IAAI,aAAa,EAAE,EAAE;AAClD,UAAM,QAAQC,yBAAU,IAAI,EAAE,MAAM,IAAI;AACxC,eAAW,KAAK,OAAO;AACrB,kBAAY,KAAK,IAAI,WAAW,EAAE,SAAS,CAAC;AAAA,IAC9C;AACA,UAAM,OAAOA,yBAAU,SAASD,gBAAe,EAAE,CAAC,EAAE,MAAM,IAAI;AAC9D,eAAW,KAAK,MAAM;AACpB,mBAAa,KAAK,IAAI,YAAY,EAAE,SAAS,CAAC;AAAA,IAChD;AAAA,EACF,CAAC;AAED,QAAM,WAAsB;AAAA,IAC1B;AAAA,MACE;AAAA,MACA,kBAAkB;AAAA;AAAA,MAClB;AAAA,MACA,cAAc;AAAA,QACZ,SAAS;AAAA,UACP,EAAC,MAAM,UAAU,OAAO,UAAA;AAAA,UACxB,EAAC,MAAM,eAAe,OAAO,WAAA;AAAA,QAAU;AAAA,QAEzC,QAAQ;AAAA,MAAA;AAAA,IACV;AAAA,EACF;AAGF,MAAI,aAAa;AACf,aAAS,QAAQ,GAAG,WAAW;AAAA,EACjC;AAEA,SAAO,OAAO,iBAAiB,QAAQ,CAAC;AAC1C;"}
|
package/out/zero/package.json.js
CHANGED
package/out/zero/src/pg.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { ApplicationError, isApplicationError, wrapWithApplicationError } from "../../zero-protocol/src/application-error.js";
|
|
2
2
|
import { customMutatorKey } from "../../zql/src/mutate/custom.js";
|
|
3
|
-
import { CRUDMutatorFactory, TransactionImpl,
|
|
3
|
+
import { CRUDMutatorFactory, TransactionImpl, makeSchemaCRUD, makeServerTransaction } from "../../zero-server/src/custom.js";
|
|
4
4
|
import { OutOfOrderMutation, getMutation, handleMutateRequest, handleMutationRequest } from "../../zero-server/src/process-mutations.js";
|
|
5
5
|
import { PushProcessor } from "../../zero-server/src/push-processor.js";
|
|
6
6
|
import { handleGetQueriesRequest, handleQueryRequest, handleTransformRequest } from "../../zero-server/src/queries/process-queries.js";
|
|
@@ -23,7 +23,6 @@ export {
|
|
|
23
23
|
handleQueryRequest,
|
|
24
24
|
handleTransformRequest,
|
|
25
25
|
isApplicationError,
|
|
26
|
-
makeMutateCRUD,
|
|
27
26
|
makeSchemaCRUD,
|
|
28
27
|
makeServerTransaction,
|
|
29
28
|
wrapWithApplicationError,
|
package/out/zero/src/server.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { ApplicationError, isApplicationError, wrapWithApplicationError } from "../../zero-protocol/src/application-error.js";
|
|
2
2
|
import { customMutatorKey } from "../../zql/src/mutate/custom.js";
|
|
3
|
-
import { CRUDMutatorFactory, TransactionImpl,
|
|
3
|
+
import { CRUDMutatorFactory, TransactionImpl, makeSchemaCRUD, makeServerTransaction } from "../../zero-server/src/custom.js";
|
|
4
4
|
import { OutOfOrderMutation, getMutation, handleMutateRequest, handleMutationRequest } from "../../zero-server/src/process-mutations.js";
|
|
5
5
|
import { PushProcessor } from "../../zero-server/src/push-processor.js";
|
|
6
6
|
import { handleGetQueriesRequest, handleQueryRequest, handleTransformRequest } from "../../zero-server/src/queries/process-queries.js";
|
|
@@ -20,7 +20,6 @@ export {
|
|
|
20
20
|
handleQueryRequest,
|
|
21
21
|
handleTransformRequest,
|
|
22
22
|
isApplicationError,
|
|
23
|
-
makeMutateCRUD,
|
|
24
23
|
makeSchemaCRUD,
|
|
25
24
|
makeServerTransaction,
|
|
26
25
|
wrapWithApplicationError
|
|
@@ -26,11 +26,11 @@ async function main() {
|
|
|
26
26
|
schema: {
|
|
27
27
|
path: {
|
|
28
28
|
type: string().optional(),
|
|
29
|
-
desc: [
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
29
|
+
desc: ["Relative path to the file containing permissions."],
|
|
30
|
+
alias: "p",
|
|
31
|
+
deprecated: [
|
|
32
|
+
"Permissions are deprecated and will be removed in an upcoming release. See: https://zero.rocicorp.dev/docs/auth."
|
|
33
|
+
]
|
|
34
34
|
}
|
|
35
35
|
},
|
|
36
36
|
...zeroOptions
|
|
@@ -131,6 +131,12 @@ async function main() {
|
|
|
131
131
|
}
|
|
132
132
|
}
|
|
133
133
|
if (config.schema.path) {
|
|
134
|
+
if (config.query.url && config.mutate.url) {
|
|
135
|
+
lc.error?.(
|
|
136
|
+
"Cannot use -p/--path/ZERO_SCHEMA_PATH flag when using ZERO_MUTATE_URL and ZERO_QUERY_URL."
|
|
137
|
+
);
|
|
138
|
+
process.exit(-1);
|
|
139
|
+
}
|
|
134
140
|
await deployPermissionsAndStartZeroCache();
|
|
135
141
|
const watcher = watch(config.schema.path, {
|
|
136
142
|
ignoreInitial: true,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"zero-cache-dev.js","sources":["../../../src/zero-cache-dev.ts"],"sourcesContent":["#!/usr/bin/env node\n\nimport '../../shared/src/dotenv.ts';\n\nimport {resolver} from '@rocicorp/resolver';\nimport {watch} from 'chokidar';\nimport {spawn, type ChildProcess} from 'node:child_process';\nimport {createLogContext} from '../../shared/src/logging.ts';\nimport {parseOptionsAdvanced} from '../../shared/src/options.ts';\nimport * as v from '../../shared/src/valita.ts';\nimport {\n ZERO_ENV_VAR_PREFIX,\n zeroOptions,\n} from '../../zero-cache/src/config/zero-config.ts';\nimport {deployPermissionsOptions} from '../../zero-cache/src/scripts/permissions.ts';\n\nconst deployPermissionsScript = 'zero-deploy-permissions';\nconst zeroCacheScript = 'zero-cache';\n\nfunction killProcess(childProcess: ChildProcess | undefined) {\n if (!childProcess || childProcess.exitCode !== null) {\n return Promise.resolve();\n }\n const {resolve, promise} = resolver();\n childProcess.on('exit', resolve);\n // Use SIGQUIT in particular since this will cause\n // a fast zero-cache shutdown instead of a graceful drain.\n childProcess.kill('SIGQUIT');\n return promise;\n}\n\nasync function main() {\n const {config} = parseOptionsAdvanced(\n {\n schema: {\n path: {\n type: v.string().optional(),\n desc: [
|
|
1
|
+
{"version":3,"file":"zero-cache-dev.js","sources":["../../../src/zero-cache-dev.ts"],"sourcesContent":["#!/usr/bin/env node\n\nimport '../../shared/src/dotenv.ts';\n\nimport {resolver} from '@rocicorp/resolver';\nimport {watch} from 'chokidar';\nimport {spawn, type ChildProcess} from 'node:child_process';\nimport {createLogContext} from '../../shared/src/logging.ts';\nimport {parseOptionsAdvanced} from '../../shared/src/options.ts';\nimport * as v from '../../shared/src/valita.ts';\nimport {\n ZERO_ENV_VAR_PREFIX,\n zeroOptions,\n} from '../../zero-cache/src/config/zero-config.ts';\nimport {deployPermissionsOptions} from '../../zero-cache/src/scripts/permissions.ts';\n\nconst deployPermissionsScript = 'zero-deploy-permissions';\nconst zeroCacheScript = 'zero-cache';\n\nfunction killProcess(childProcess: ChildProcess | undefined) {\n if (!childProcess || childProcess.exitCode !== null) {\n return Promise.resolve();\n }\n const {resolve, promise} = resolver();\n childProcess.on('exit', resolve);\n // Use SIGQUIT in particular since this will cause\n // a fast zero-cache shutdown instead of a graceful drain.\n childProcess.kill('SIGQUIT');\n return promise;\n}\n\nasync function main() {\n const {config} = parseOptionsAdvanced(\n {\n schema: {\n path: {\n type: v.string().optional(),\n desc: ['Relative path to the file containing permissions.'],\n alias: 'p',\n deprecated: [\n 'Permissions are deprecated and will be removed in an upcoming release. See: https://zero.rocicorp.dev/docs/auth.',\n ],\n },\n },\n ...zeroOptions,\n },\n {\n envNamePrefix: ZERO_ENV_VAR_PREFIX,\n // TODO: This may no longer be necessary since multi-tenant was removed.\n allowPartial: true, // required by server/runner/config.ts\n },\n );\n\n const lc = createLogContext(config);\n\n process.on('unhandledRejection', reason => {\n lc.error?.('Unexpected unhandled rejection.', reason);\n lc.error?.('Exiting');\n process.exit(-1);\n });\n\n // Parse options for each subprocess to get environment variables\n const {env: deployPermissionsEnv} = parseOptionsAdvanced(\n deployPermissionsOptions,\n {\n envNamePrefix: ZERO_ENV_VAR_PREFIX,\n allowUnknown: true,\n includeDefaults: false,\n },\n );\n const {env: zeroCacheEnv} = parseOptionsAdvanced(zeroOptions, {\n envNamePrefix: ZERO_ENV_VAR_PREFIX,\n allowUnknown: true,\n includeDefaults: false,\n });\n\n let permissionsProcess: ChildProcess | undefined;\n let zeroCacheProcess: ChildProcess | undefined;\n\n // Ensure child processes are killed when the main process exits\n process.on('exit', () => {\n permissionsProcess?.kill('SIGQUIT');\n zeroCacheProcess?.kill('SIGQUIT');\n });\n\n async function deployPermissions(): Promise<boolean> {\n if (config.upstream.type !== 'pg') {\n lc.warn?.(\n `Skipping permissions deployment for ${config.upstream.type} upstream`,\n );\n return true;\n }\n permissionsProcess?.removeAllListeners('exit');\n await killProcess(permissionsProcess);\n permissionsProcess = undefined;\n\n lc.info?.(`Running ${deployPermissionsScript}.`);\n permissionsProcess = spawn(deployPermissionsScript, [], {\n env: {...process.env, ...deployPermissionsEnv},\n stdio: 'inherit',\n shell: true,\n });\n\n const {promise: code, resolve} = resolver<number>();\n permissionsProcess.on('exit', resolve);\n if ((await code) === 0) {\n lc.info?.(`${deployPermissionsScript} completed successfully.`);\n return true;\n }\n lc.error?.(`Failed to deploy permissions from ${config.schema.path}.`);\n return false;\n }\n\n async function startZeroCache() {\n zeroCacheProcess?.removeAllListeners('exit');\n await killProcess(zeroCacheProcess);\n zeroCacheProcess = undefined;\n\n lc.info?.(\n `Running ${zeroCacheScript} at\\n\\n\\thttp://localhost:${config.port}\\n`,\n );\n const env: NodeJS.ProcessEnv = {\n // Set some low defaults so as to use fewer resources and not trip up,\n // e.g. developers sharing a database.\n ['ZERO_NUM_SYNC_WORKERS']: '3',\n ['ZERO_CVR_MAX_CONNS']: '6',\n ['ZERO_UPSTREAM_MAX_CONNS']: '6',\n\n // Default NODE_ENV to development mode.\n // @ts-ignore NODE_ENV is not always set. Please ignore error.\n ['NODE_ENV']: 'development',\n\n // But let the developer override any of these dev defaults.\n ...process.env,\n ...zeroCacheEnv,\n };\n zeroCacheProcess = spawn(zeroCacheScript, [], {\n env,\n stdio: 'inherit',\n shell: true,\n });\n zeroCacheProcess.on('exit', () => {\n lc.error?.(`${zeroCacheScript} exited. Exiting.`);\n process.exit(-1);\n });\n }\n\n async function deployPermissionsAndStartZeroCache() {\n if (await deployPermissions()) {\n await startZeroCache();\n }\n }\n\n if (config.schema.path) {\n if (config.query.url && config.mutate.url) {\n lc.error?.(\n 'Cannot use -p/--path/ZERO_SCHEMA_PATH flag when using ZERO_MUTATE_URL and ZERO_QUERY_URL.',\n );\n process.exit(-1);\n }\n\n await deployPermissionsAndStartZeroCache();\n\n // Watch for file changes\n const watcher = watch(config.schema.path, {\n ignoreInitial: true,\n awaitWriteFinish: {stabilityThreshold: 500, pollInterval: 100},\n });\n const onFileChange = async () => {\n lc.info?.(`Detected ${config.schema.path} change.`);\n await deployPermissions();\n };\n watcher.on('add', onFileChange);\n watcher.on('change', onFileChange);\n watcher.on('unlink', onFileChange);\n } else {\n await startZeroCache();\n }\n}\n\nvoid main();\n"],"names":["v.string"],"mappings":"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"}
|