@open-mercato/shared 0.6.7-develop.6860.1.f796b22e80 → 0.6.7
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/.turbo/turbo-build.log +1 -1
- package/AGENTS.md +6 -57
- package/build.mjs +4 -2
- package/dist/lib/auth/server.js +2 -15
- package/dist/lib/auth/server.js.map +2 -2
- package/dist/lib/bootstrap/dynamicLoader.js +43 -117
- package/dist/lib/bootstrap/dynamicLoader.js.map +2 -2
- package/dist/lib/commands/command-bus.js +1 -5
- package/dist/lib/commands/command-bus.js.map +2 -2
- package/dist/lib/commands/command-interceptor-runner.js +2 -2
- package/dist/lib/commands/command-interceptor-runner.js.map +2 -2
- package/dist/lib/crud/enricher-runner.js +11 -2
- package/dist/lib/crud/enricher-runner.js.map +2 -2
- package/dist/lib/crud/factory.js +4 -63
- package/dist/lib/crud/factory.js.map +2 -2
- package/dist/lib/crud/interceptor-runner.js +2 -2
- package/dist/lib/crud/interceptor-runner.js.map +2 -2
- package/dist/lib/crud/mutation-guard-registry.js +2 -2
- package/dist/lib/crud/mutation-guard-registry.js.map +2 -2
- package/dist/lib/crud/types.js +0 -4
- package/dist/lib/crud/types.js.map +3 -3
- package/dist/lib/data/engine.js +11 -37
- package/dist/lib/data/engine.js.map +2 -2
- package/dist/lib/db/mikro.js +12 -3
- package/dist/lib/db/mikro.js.map +2 -2
- package/dist/lib/db/pg-errors.js +0 -42
- package/dist/lib/db/pg-errors.js.map +2 -2
- package/dist/lib/di/container.js +6 -48
- package/dist/lib/di/container.js.map +2 -2
- package/dist/lib/email/send.js +0 -56
- package/dist/lib/email/send.js.map +2 -2
- package/dist/lib/encryption/subscriber.js +10 -2
- package/dist/lib/encryption/subscriber.js.map +2 -2
- package/dist/lib/encryption/tenantDataEncryptionService.js +17 -52
- package/dist/lib/encryption/tenantDataEncryptionService.js.map +2 -2
- package/dist/lib/i18n/config.js +1 -1
- package/dist/lib/i18n/config.js.map +2 -2
- package/dist/lib/i18n/server.js +4 -4
- package/dist/lib/i18n/server.js.map +3 -3
- package/dist/lib/logger/index.js +3 -47
- package/dist/lib/logger/index.js.map +3 -3
- package/dist/lib/modules/registry.js +1 -5
- package/dist/lib/modules/registry.js.map +2 -2
- package/dist/lib/query/engine.js +40 -54
- package/dist/lib/query/engine.js.map +2 -2
- package/dist/lib/query/types.js.map +1 -1
- package/dist/lib/redis/connection.js +2 -7
- package/dist/lib/redis/connection.js.map +2 -2
- package/dist/lib/search/config.js +2 -61
- package/dist/lib/search/config.js.map +2 -2
- package/dist/lib/search/tokenize.js +11 -23
- package/dist/lib/search/tokenize.js.map +2 -2
- package/dist/lib/version.js +1 -1
- package/dist/lib/version.js.map +1 -1
- package/dist/lib/webhooks/index.js +1 -13
- package/dist/lib/webhooks/index.js.map +2 -2
- package/dist/lib/webhooks/verify.js +7 -12
- package/dist/lib/webhooks/verify.js.map +2 -2
- package/dist/modules/analytics.js.map +2 -2
- package/dist/modules/overrides.js +1 -50
- package/dist/modules/overrides.js.map +2 -2
- package/dist/modules/payment_gateways/types.js +1 -8
- package/dist/modules/payment_gateways/types.js.map +2 -2
- package/dist/modules/registry.js +0 -1
- package/dist/modules/registry.js.map +2 -2
- package/dist/security/enabledModulesRegistry.js +11 -56
- package/dist/security/enabledModulesRegistry.js.map +2 -2
- package/jest.config.cjs +1 -2
- package/package.json +9 -19
- package/src/lib/ai/llm-provider.ts +0 -33
- package/src/lib/auth/__tests__/server.test.ts +0 -23
- package/src/lib/auth/server.ts +2 -23
- package/src/lib/bootstrap/__tests__/dynamicLoader.commandInterceptors.test.ts +8 -63
- package/src/lib/bootstrap/__tests__/dynamicLoader.tsconfig.test.ts +1 -21
- package/src/lib/bootstrap/dynamicLoader.ts +65 -213
- package/src/lib/commands/__tests__/command-interceptor-runner.test.ts +0 -28
- package/src/lib/commands/command-bus.ts +1 -5
- package/src/lib/commands/command-interceptor-runner.ts +2 -2
- package/src/lib/crud/__tests__/crud-factory.test.ts +0 -298
- package/src/lib/crud/__tests__/mutation-guard-registry.test.ts +0 -26
- package/src/lib/crud/enricher-runner.ts +11 -2
- package/src/lib/crud/factory.ts +1 -69
- package/src/lib/crud/interceptor-runner.ts +2 -2
- package/src/lib/crud/mutation-guard-registry.ts +2 -2
- package/src/lib/crud/types.ts +0 -3
- package/src/lib/data/__tests__/engine.bulk-suppress.test.ts +3 -18
- package/src/lib/data/engine.ts +16 -50
- package/src/lib/db/__tests__/mikro.test.ts +25 -0
- package/src/lib/db/mikro.ts +38 -13
- package/src/lib/db/pg-errors.ts +0 -58
- package/src/lib/di/container.ts +8 -72
- package/src/lib/email/__tests__/send.test.ts +1 -37
- package/src/lib/email/send.ts +0 -79
- package/src/lib/encryption/__tests__/subscriber.test.ts +2 -54
- package/src/lib/encryption/__tests__/tenantDataEncryptionService.test.ts +0 -58
- package/src/lib/encryption/subscriber.ts +14 -2
- package/src/lib/encryption/tenantDataEncryptionService.ts +18 -64
- package/src/lib/i18n/config.ts +2 -2
- package/src/lib/i18n/server.ts +2 -6
- package/src/lib/logger/__tests__/logger.test.ts +0 -77
- package/src/lib/logger/index.ts +1 -59
- package/src/lib/modules/registry.ts +0 -10
- package/src/lib/query/__tests__/engine.test.ts +13 -65
- package/src/lib/query/engine.ts +58 -75
- package/src/lib/query/types.ts +5 -4
- package/src/lib/redis/__tests__/connection.test.ts +0 -16
- package/src/lib/redis/connection.ts +7 -10
- package/src/lib/search/__tests__/config.test.ts +0 -177
- package/src/lib/search/config.ts +8 -106
- package/src/lib/search/tokenize.ts +11 -33
- package/src/lib/webhooks/__tests__/verify.test.ts +1 -20
- package/src/lib/webhooks/index.ts +1 -19
- package/src/lib/webhooks/verify.ts +9 -17
- package/src/modules/__tests__/registry.test.ts +2 -10
- package/src/modules/analytics.ts +0 -7
- package/src/modules/customer-auth.ts +0 -1
- package/src/modules/encryption.ts +0 -3
- package/src/modules/navigation/backendChrome.ts +0 -15
- package/src/modules/overrides.ts +0 -103
- package/src/modules/payment_gateways/types.ts +0 -41
- package/src/modules/registry.ts +0 -3
- package/src/security/enabledModulesRegistry.ts +12 -64
- package/dist/lib/ai/safety-identifier.js +0 -32
- package/dist/lib/ai/safety-identifier.js.map +0 -7
- package/dist/lib/auth/organizationScope.js +0 -34
- package/dist/lib/auth/organizationScope.js.map +0 -7
- package/dist/lib/bootstrap/clientOnlyModules.js +0 -55
- package/dist/lib/bootstrap/clientOnlyModules.js.map +0 -7
- package/dist/lib/data/consistency.js +0 -19
- package/dist/lib/data/consistency.js.map +0 -7
- package/dist/lib/db/entityMetadata.js +0 -26
- package/dist/lib/db/entityMetadata.js.map +0 -7
- package/dist/lib/logger/extension.js +0 -29
- package/dist/lib/logger/extension.js.map +0 -7
- package/dist/lib/modules/surfaceFingerprint.js +0 -47
- package/dist/lib/modules/surfaceFingerprint.js.map +0 -7
- package/dist/lib/query/ciphertext-search-warning.js +0 -45
- package/dist/lib/query/ciphertext-search-warning.js.map +0 -7
- package/dist/lib/search/auto-indexing.js +0 -14
- package/dist/lib/search/auto-indexing.js.map +0 -7
- package/dist/lib/search/availability.js +0 -107
- package/dist/lib/search/availability.js.map +0 -7
- package/dist/lib/search/tokenLookup.js +0 -46
- package/dist/lib/search/tokenLookup.js.map +0 -7
- package/dist/lib/telemetry/runtime.js +0 -35
- package/dist/lib/telemetry/runtime.js.map +0 -7
- package/dist/lib/webhooks/body.js +0 -57
- package/dist/lib/webhooks/body.js.map +0 -7
- package/dist/lib/webhooks/inbound-types.js +0 -1
- package/dist/lib/webhooks/inbound-types.js.map +0 -7
- package/dist/modules/widgets/extension-points.js +0 -96
- package/dist/modules/widgets/extension-points.js.map +0 -7
- package/dist/security/featurePolicy.js +0 -62
- package/dist/security/featurePolicy.js.map +0 -7
- package/scripts/versionSource.cjs +0 -65
- package/src/lib/__tests__/versionSource.test.ts +0 -46
- package/src/lib/ai/__tests__/llm-provider-contract.test.ts +0 -59
- package/src/lib/ai/__tests__/safety-identifier.test.ts +0 -71
- package/src/lib/ai/safety-identifier.ts +0 -73
- package/src/lib/auth/__tests__/organizationScope.test.ts +0 -107
- package/src/lib/auth/organizationScope.ts +0 -65
- package/src/lib/bootstrap/__tests__/clientOnlyModules.test.ts +0 -189
- package/src/lib/bootstrap/__tests__/dynamicLoader.aliasResolver.test.ts +0 -98
- package/src/lib/bootstrap/__tests__/dynamicLoader.appDi.test.ts +0 -211
- package/src/lib/bootstrap/__tests__/dynamicLoader.generatedCacheRecovery.test.ts +0 -192
- package/src/lib/bootstrap/clientOnlyModules.ts +0 -85
- package/src/lib/crud/__tests__/crud-factory.cache-user-scope.test.ts +0 -171
- package/src/lib/data/__tests__/consistency.test.ts +0 -38
- package/src/lib/data/consistency.ts +0 -17
- package/src/lib/db/__tests__/entityMetadata.test.ts +0 -38
- package/src/lib/db/__tests__/pg-errors.test.ts +0 -48
- package/src/lib/db/entityMetadata.ts +0 -43
- package/src/lib/di/__tests__/container-app-di-absent.test.ts +0 -155
- package/src/lib/di/__tests__/container-app-di.test.ts +0 -173
- package/src/lib/di/__tests__/registrar-error-log.test.ts +0 -154
- package/src/lib/i18n/__tests__/config.test.ts +0 -8
- package/src/lib/i18n/__tests__/server-dictionary-cache.test.ts +0 -30
- package/src/lib/i18n/__tests__/server-unbootstrapped.test.ts +0 -29
- package/src/lib/logger/extension.ts +0 -59
- package/src/lib/modules/__tests__/surfaceFingerprint.test.ts +0 -122
- package/src/lib/modules/surfaceFingerprint.ts +0 -87
- package/src/lib/query/__tests__/ciphertext-search-warning.test.ts +0 -178
- package/src/lib/query/ciphertext-search-warning.ts +0 -95
- package/src/lib/search/__tests__/availability.test.ts +0 -211
- package/src/lib/search/__tests__/tokenLookup.test.ts +0 -206
- package/src/lib/search/__tests__/tokenize.test.ts +0 -49
- package/src/lib/search/auto-indexing.ts +0 -22
- package/src/lib/search/availability.ts +0 -232
- package/src/lib/search/tokenLookup.ts +0 -133
- package/src/lib/telemetry/runtime.ts +0 -72
- package/src/lib/webhooks/__tests__/body.test.ts +0 -95
- package/src/lib/webhooks/body.ts +0 -70
- package/src/lib/webhooks/inbound-types.ts +0 -125
- package/src/modules/__tests__/nav-group-order-override.test.ts +0 -183
- package/src/modules/payment_gateways/__tests__/types.test.ts +0 -37
- package/src/modules/widgets/__tests__/extension-points.test.ts +0 -101
- package/src/modules/widgets/extension-points.ts +0 -524
- package/src/security/__tests__/featurePolicy.test.ts +0 -166
- package/src/security/featurePolicy.ts +0 -89
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../../src/lib/query/types.ts"],
|
|
4
|
-
"sourcesContent": ["import type { EntityId } from '@open-mercato/shared/modules/entities'\nimport type { Profiler } from '../profiler'\nimport type { ResolvedCustomFieldDefinitions } from '../crud/custom-field-definition-index'\n\nexport type FilterOp = 'eq' | 'ne' | 'gt' | 'gte' | 'lt' | 'lte' | 'in' | 'nin' | 'like' | 'ilike' | 'exists'\n\nexport enum SortDir {\n Asc = 'asc',\n Desc = 'desc',\n}\n\nexport type FieldSelector = string // base field or custom field key (prefixed with 'cf:')\n\nexport type Filter = {\n field: FieldSelector\n op: FilterOp\n value?: any\n}\n\nexport type Sort = { field: FieldSelector; dir?: SortDir }\n\nexport type Page = { page?: number; pageSize?: number }\n\n// Mongo/Medusa-style filter operators (typed)\nexport type WhereOps<T> = {\n $eq?: T\n $ne?: T | null\n $gt?: T extends number | Date ? T : never\n $gte?: T extends number | Date ? T : never\n $lt?: T extends number | Date ? T : never\n $lte?: T extends number | Date ? T : never\n $in?: T[]\n $nin?: T[]\n $like?: T extends string ? string : never\n $ilike?: T extends string ? string : never\n $exists?: boolean\n}\n\n// A field filter can be a direct value (equals) or ops object\nexport type WhereValue<T = any> = T | WhereOps<T>\n\n// Generic shape for object filters. If you have a typed map of field\u2192type,\n// pass it as the generic to get end-to-end typing.\n// Example: Where<{\n// id: string; title: string; created_at: Date; 'cf:severity': number\n// }>\nexport type Where<Fields extends Record<string, any> = Record<string, any>> =\n Partial<{ [K in keyof Fields]: WhereValue<Fields[K]> }> & Record<string, WhereValue>\n\nexport type QueryCustomFieldJoin = {\n fromField: string\n toField: string\n type?: 'left' | 'inner'\n}\n\nexport type QueryCustomFieldSource = {\n entityId: EntityId\n table?: string\n alias?: string\n recordIdColumn?: string\n join?: QueryCustomFieldJoin\n tenantField?: string\n organizationField?: string\n}\n\nexport type QueryJoinEdge = {\n alias: string\n table?: string\n entityId?: EntityId\n from: {\n alias?: string\n field: string\n }\n to: {\n field: string\n }\n type?: 'left' | 'inner'\n}\n\n/**\n * Optional context for query-level UMES extensions.\n * When provided, the query engine will execute sync lifecycle events\n * (querying/queried) and apply query-enabled enrichers.\n */\nexport type QueryExtensionsConfig = {\n userId?: string\n container?: unknown\n userFeatures?: string[]\n resolve?: <T = unknown>(name: string) => T\n}\n\nexport type QueryOptions = {\n fields?: FieldSelector[] // base fields and/or 'cf:<key>' for custom fields\n includeExtensions?: boolean | string[] // include all registered extensions or only specific ones by entity id\n includeCustomFields?: boolean | string[] // include all CFs or specific keys\n // Accept classic array syntax or Mongo-style object syntax\n filters?: Filter[] | Where\n sort?: Sort[]\n page?: Page\n organizationId?: string // enforce multi-tenant scope\n tenantId?: string // enforce tenant scope\n // Optional list of organization ids to scope results. Takes precedence over organizationId.\n organizationIds?: string[]\n /**\n * When true, the engine does not apply default `organization_id` / `tenant_id` equality guards.\n *\n * Callers MUST encode full visibility in `filters` (for example with `$or` of scoped branches)\n * and MUST fail closed when the authenticated principal lacks a resolvable tenant/org, otherwise\n * queries return cross-tenant rows.\n *\n * When this flag is set, the hybrid query engine delegates to the basic engine
|
|
4
|
+
"sourcesContent": ["import type { EntityId } from '@open-mercato/shared/modules/entities'\nimport type { Profiler } from '../profiler'\nimport type { ResolvedCustomFieldDefinitions } from '../crud/custom-field-definition-index'\n\nexport type FilterOp = 'eq' | 'ne' | 'gt' | 'gte' | 'lt' | 'lte' | 'in' | 'nin' | 'like' | 'ilike' | 'exists'\n\nexport enum SortDir {\n Asc = 'asc',\n Desc = 'desc',\n}\n\nexport type FieldSelector = string // base field or custom field key (prefixed with 'cf:')\n\nexport type Filter = {\n field: FieldSelector\n op: FilterOp\n value?: any\n}\n\nexport type Sort = { field: FieldSelector; dir?: SortDir }\n\nexport type Page = { page?: number; pageSize?: number }\n\n// Mongo/Medusa-style filter operators (typed)\nexport type WhereOps<T> = {\n $eq?: T\n $ne?: T | null\n $gt?: T extends number | Date ? T : never\n $gte?: T extends number | Date ? T : never\n $lt?: T extends number | Date ? T : never\n $lte?: T extends number | Date ? T : never\n $in?: T[]\n $nin?: T[]\n $like?: T extends string ? string : never\n $ilike?: T extends string ? string : never\n $exists?: boolean\n}\n\n// A field filter can be a direct value (equals) or ops object\nexport type WhereValue<T = any> = T | WhereOps<T>\n\n// Generic shape for object filters. If you have a typed map of field\u2192type,\n// pass it as the generic to get end-to-end typing.\n// Example: Where<{\n// id: string; title: string; created_at: Date; 'cf:severity': number\n// }>\nexport type Where<Fields extends Record<string, any> = Record<string, any>> =\n Partial<{ [K in keyof Fields]: WhereValue<Fields[K]> }> & Record<string, WhereValue>\n\nexport type QueryCustomFieldJoin = {\n fromField: string\n toField: string\n type?: 'left' | 'inner'\n}\n\nexport type QueryCustomFieldSource = {\n entityId: EntityId\n table?: string\n alias?: string\n recordIdColumn?: string\n join?: QueryCustomFieldJoin\n tenantField?: string\n organizationField?: string\n}\n\nexport type QueryJoinEdge = {\n alias: string\n table?: string\n entityId?: EntityId\n from: {\n alias?: string\n field: string\n }\n to: {\n field: string\n }\n type?: 'left' | 'inner'\n}\n\n/**\n * Optional context for query-level UMES extensions.\n * When provided, the query engine will execute sync lifecycle events\n * (querying/queried) and apply query-enabled enrichers.\n */\nexport type QueryExtensionsConfig = {\n userId?: string\n container?: unknown\n userFeatures?: string[]\n resolve?: <T = unknown>(name: string) => T\n}\n\nexport type QueryOptions = {\n fields?: FieldSelector[] // base fields and/or 'cf:<key>' for custom fields\n includeExtensions?: boolean | string[] // include all registered extensions or only specific ones by entity id\n includeCustomFields?: boolean | string[] // include all CFs or specific keys\n // Accept classic array syntax or Mongo-style object syntax\n filters?: Filter[] | Where\n sort?: Sort[]\n page?: Page\n organizationId?: string // enforce multi-tenant scope\n tenantId?: string // enforce tenant scope\n // Optional list of organization ids to scope results. Takes precedence over organizationId.\n organizationIds?: string[]\n /**\n * When true, the engine does not apply default `organization_id` / `tenant_id` equality guards.\n *\n * Callers MUST encode full visibility in `filters` (for example with `$or` of scoped branches)\n * and MUST fail closed when the authenticated principal lacks a resolvable tenant/org, otherwise\n * queries return cross-tenant rows.\n *\n * When this flag is set, the hybrid query engine delegates to the basic engine, which means\n * custom-field (`cf:*`) filters/sorts, `search_tokens` fulltext filtering, and vector-search\n * branches are BYPASSED. Only use this on entities whose scoping does not match the standard\n * `organization_id = X AND tenant_id = Y` shape and which do not rely on custom-field/search\n * features.\n */\n omitAutomaticTenantOrgScope?: boolean\n // Soft-delete behavior: when false (default), rows with non-null deleted_at\n // are excluded if the base table has that column. Set true to include them.\n withDeleted?: boolean\n customFieldSources?: QueryCustomFieldSource[]\n joins?: QueryJoinEdge[]\n profiler?: Profiler\n // When true, suppress automatic reindex scheduling triggered by coverage gap detection.\n // Used by the search indexing pipeline to prevent feedback loops where indexing triggers\n // re-indexing indefinitely.\n skipAutoReindex?: boolean\n /**\n * Force routing this query to custom-entity doc storage (`custom_entities_storage`)\n * instead of classifying the entity automatically. Automatic classification routes\n * ids backed by a registered ORM table to that base table, so surfaces that manage\n * doc records for ids that are ALSO table-backed (e.g. the entities records browser\n * reading a module-declared custom entity such as `example:todo`) must set this flag.\n * Honored by the hybrid query engine only; `BasicQueryEngine` has no doc-storage\n * reader and ignores it.\n */\n forceCustomEntityStorage?: boolean\n // Optional UMES query extensions context. When provided, the engine will\n // emit sync lifecycle events and apply query-level enrichers.\n extensions?: QueryExtensionsConfig\n}\n\nexport type PartialIndexWarning = {\n entity: EntityId\n entityLabel?: string | null\n baseCount?: number | null\n indexedCount?: number | null\n scope?: 'scoped' | 'global'\n}\n\nexport type EncryptedSortRowCapWarning = {\n entity: EntityId\n sortFields: string[]\n maxRows: number\n totalMatched: number\n}\n\nexport type QueryResultMeta = {\n partialIndexWarning?: PartialIndexWarning\n encryptedSortRowCapWarning?: EncryptedSortRowCapWarning\n}\n\nexport type QueryResult<T = any> = {\n items: T[]\n page: number\n pageSize: number\n total: number\n meta?: QueryResultMeta\n /**\n * Custom-field definitions the engine resolved while building this result\n * (only present when `includeCustomFields: true`). Lets the CRUD factory\n * decorate list rows without reloading definitions from the DB (issue #2133).\n * Internal contract \u2014 additive and optional; callers must treat absence as a\n * cue to load definitions themselves.\n */\n customFieldDefinitions?: ResolvedCustomFieldDefinitions\n}\n\nexport interface QueryEngine {\n query<T = any>(entity: EntityId, opts?: QueryOptions): Promise<QueryResult<T>>\n}\n"],
|
|
5
5
|
"mappings": "AAMO,IAAK,UAAL,kBAAKA,aAAL;AACL,EAAAA,SAAA,SAAM;AACN,EAAAA,SAAA,UAAO;AAFG,SAAAA;AAAA,GAAA;",
|
|
6
6
|
"names": ["SortDir"]
|
|
7
7
|
}
|
|
@@ -21,17 +21,12 @@ function parseRedisUrl(url) {
|
|
|
21
21
|
const dbStr = parsed.pathname ? parsed.pathname.slice(1) : "";
|
|
22
22
|
const dbParsed = dbStr !== "" ? parseInt(dbStr, 10) : NaN;
|
|
23
23
|
const db = Number.isNaN(dbParsed) ? void 0 : dbParsed;
|
|
24
|
-
const familyValue = parsed.searchParams.get("family");
|
|
25
|
-
const familyParsed = familyValue !== null ? parseInt(familyValue, 10) : NaN;
|
|
26
|
-
const family = [0, 4, 6].includes(familyParsed) ? familyParsed : void 0;
|
|
27
24
|
return {
|
|
28
25
|
host: parsed.hostname || "localhost",
|
|
29
26
|
port: parseInt(parsed.port, 10) || 6379,
|
|
30
|
-
|
|
31
|
-
password: parsed.password ? decodeURIComponent(parsed.password) : void 0,
|
|
27
|
+
password: parsed.password || void 0,
|
|
32
28
|
db,
|
|
33
|
-
tls: parsed.protocol === "rediss:" ? {} : void 0
|
|
34
|
-
family
|
|
29
|
+
tls: parsed.protocol === "rediss:" ? {} : void 0
|
|
35
30
|
};
|
|
36
31
|
} catch {
|
|
37
32
|
const safeUrl = url.replace(/\/\/[^:]*:[^@]*@/, "//<redacted>@");
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../../src/lib/redis/connection.ts"],
|
|
4
|
-
"sourcesContent": ["import { createLogger } from '../logger'\n\nconst logger = createLogger('shared').child({ component: 'redis' })\n\n/**\n * Shared Redis connection utilities.\n *\n * Every package that needs a Redis URL or parsed connection options\n * should import from here instead of reading env vars directly.\n *\n * The `prefix` parameter lets each subsystem define its own override:\n * getRedisUrl('QUEUE') \u2192 QUEUE_REDIS_URL > REDIS_URL > null\n * getRedisUrl('CACHE') \u2192 CACHE_REDIS_URL > REDIS_URL > null\n * getRedisUrl() \u2192 REDIS_URL > null\n *\n * Returns null when Redis is not configured so callers can explicitly\n * decide whether to fall back to a non-Redis strategy or fail loudly.\n * Use getRedisUrlOrThrow() when Redis is mandatory for the caller.\n */\n\nexport type ParsedRedisConnection = {\n host: string\n port: number\n
|
|
5
|
-
"mappings": "AAAA,SAAS,oBAAoB;AAE7B,MAAM,SAAS,aAAa,QAAQ,EAAE,MAAM,EAAE,WAAW,QAAQ,CAAC;
|
|
4
|
+
"sourcesContent": ["import { createLogger } from '../logger'\n\nconst logger = createLogger('shared').child({ component: 'redis' })\n\n/**\n * Shared Redis connection utilities.\n *\n * Every package that needs a Redis URL or parsed connection options\n * should import from here instead of reading env vars directly.\n *\n * The `prefix` parameter lets each subsystem define its own override:\n * getRedisUrl('QUEUE') \u2192 QUEUE_REDIS_URL > REDIS_URL > null\n * getRedisUrl('CACHE') \u2192 CACHE_REDIS_URL > REDIS_URL > null\n * getRedisUrl() \u2192 REDIS_URL > null\n *\n * Returns null when Redis is not configured so callers can explicitly\n * decide whether to fall back to a non-Redis strategy or fail loudly.\n * Use getRedisUrlOrThrow() when Redis is mandatory for the caller.\n */\n\nexport type ParsedRedisConnection = {\n host: string\n port: number\n password?: string\n db?: number\n tls?: Record<string, unknown>\n}\n\n/**\n * Resolve a Redis URL from environment variables.\n *\n * Priority: <PREFIX>_REDIS_URL \u2192 REDIS_URL \u2192 null\n *\n * Returns null when no env var is set. Callers MUST NOT assume a\n * localhost default \u2014 silently connecting to localhost masks missing\n * configuration and stalls on platforms where nothing listens there\n * (e.g., WSL2 without a local Redis).\n */\nexport function getRedisUrl(prefix?: string): string | null {\n if (prefix) {\n const prefixed = process.env[`${prefix}_REDIS_URL`]\n if (prefixed) return prefixed\n }\n return process.env.REDIS_URL || null\n}\n\n/**\n * Like getRedisUrl, but throws a descriptive error when Redis is not\n * configured. Use from code paths that require Redis (e.g. BullMQ\n * async queue, Redis cache strategy, scheduler service).\n */\nexport function getRedisUrlOrThrow(prefix?: string): string {\n const url = getRedisUrl(prefix)\n if (url) return url\n const which = prefix ? `${prefix}_REDIS_URL or REDIS_URL` : 'REDIS_URL'\n throw new Error(\n `Redis URL is not configured. Set ${which} in your environment to use a Redis-backed strategy.`\n )\n}\n\n/**\n * Parse a redis:// URL into a {host, port, password, db} object\n * suitable for BullMQ / ioredis structured connection options.\n *\n * @deprecated Prefer passing the full URL via `{ url: getRedisUrl(...) }` to\n * BullMQ/ioredis \u2014 this preserves rediss://, username, database, and query\n * params that structured parsing may lose. Kept for backward compatibility.\n */\nexport function parseRedisUrl(url: string): ParsedRedisConnection {\n try {\n const parsed = new URL(url)\n const dbStr = parsed.pathname ? parsed.pathname.slice(1) : ''\n const dbParsed = dbStr !== '' ? parseInt(dbStr, 10) : NaN\n const db = Number.isNaN(dbParsed) ? undefined : dbParsed\n return {\n host: parsed.hostname || 'localhost',\n port: parseInt(parsed.port, 10) || 6379,\n password: parsed.password || undefined,\n db,\n tls: parsed.protocol === 'rediss:' ? {} : undefined,\n }\n } catch {\n const safeUrl = url.replace(/\\/\\/[^:]*:[^@]*@/, '//<redacted>@')\n logger.warn('Failed to parse Redis URL, falling back to localhost:6379', { url: safeUrl })\n return { host: 'localhost', port: 6379 }\n }\n}\n\n/**\n * Convenience: resolve the URL from env and parse it in one step.\n * Returns null when Redis is not configured.\n */\nexport function resolveRedisConnection(\n prefix?: string,\n): (ParsedRedisConnection & { url: string }) | null {\n const url = getRedisUrl(prefix)\n if (!url) return null\n return { url, ...parseRedisUrl(url) }\n}\n"],
|
|
5
|
+
"mappings": "AAAA,SAAS,oBAAoB;AAE7B,MAAM,SAAS,aAAa,QAAQ,EAAE,MAAM,EAAE,WAAW,QAAQ,CAAC;AAoC3D,SAAS,YAAY,QAAgC;AAC1D,MAAI,QAAQ;AACV,UAAM,WAAW,QAAQ,IAAI,GAAG,MAAM,YAAY;AAClD,QAAI,SAAU,QAAO;AAAA,EACvB;AACA,SAAO,QAAQ,IAAI,aAAa;AAClC;AAOO,SAAS,mBAAmB,QAAyB;AAC1D,QAAM,MAAM,YAAY,MAAM;AAC9B,MAAI,IAAK,QAAO;AAChB,QAAM,QAAQ,SAAS,GAAG,MAAM,4BAA4B;AAC5D,QAAM,IAAI;AAAA,IACR,oCAAoC,KAAK;AAAA,EAC3C;AACF;AAUO,SAAS,cAAc,KAAoC;AAChE,MAAI;AACF,UAAM,SAAS,IAAI,IAAI,GAAG;AAC1B,UAAM,QAAQ,OAAO,WAAW,OAAO,SAAS,MAAM,CAAC,IAAI;AAC3D,UAAM,WAAW,UAAU,KAAK,SAAS,OAAO,EAAE,IAAI;AACtD,UAAM,KAAK,OAAO,MAAM,QAAQ,IAAI,SAAY;AAChD,WAAO;AAAA,MACL,MAAM,OAAO,YAAY;AAAA,MACzB,MAAM,SAAS,OAAO,MAAM,EAAE,KAAK;AAAA,MACnC,UAAU,OAAO,YAAY;AAAA,MAC7B;AAAA,MACA,KAAK,OAAO,aAAa,YAAY,CAAC,IAAI;AAAA,IAC5C;AAAA,EACF,QAAQ;AACN,UAAM,UAAU,IAAI,QAAQ,oBAAoB,eAAe;AAC/D,WAAO,KAAK,6DAA6D,EAAE,KAAK,QAAQ,CAAC;AACzF,WAAO,EAAE,MAAM,aAAa,MAAM,KAAK;AAAA,EACzC;AACF;AAMO,SAAS,uBACd,QACkD;AAClD,QAAM,MAAM,YAAY,MAAM;AAC9B,MAAI,CAAC,IAAK,QAAO;AACjB,SAAO,EAAE,KAAK,GAAG,cAAc,GAAG,EAAE;AACtC;",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|
|
@@ -1,94 +1,35 @@
|
|
|
1
1
|
import { parseBooleanWithDefault } from "@open-mercato/shared/lib/boolean";
|
|
2
2
|
import { parseNumberWithDefault } from "@open-mercato/shared/lib/number";
|
|
3
|
-
import { parseCommaSeparatedList } from "@open-mercato/shared/lib/string";
|
|
4
3
|
const DEFAULT_SEARCH_MIN_TOKEN_LENGTH = 3;
|
|
5
|
-
const DEFAULT_SEARCH_MAX_FIELD_CHARS = 2e4;
|
|
6
|
-
const DEFAULT_SEARCH_MAX_TOKENS_PER_FIELD = 5e3;
|
|
7
|
-
const DEFAULT_SEARCH_MAX_TOKENS_PER_RECORD = 2e4;
|
|
8
4
|
const DEFAULT_BLOCKLIST = ["password", "token", "secret", "hash"];
|
|
9
|
-
const ENTITY_BLOCKLIST_SEPARATOR = "@";
|
|
10
5
|
function parseBoolean(raw, fallback) {
|
|
11
6
|
return parseBooleanWithDefault(raw, fallback);
|
|
12
7
|
}
|
|
13
8
|
function parseNumber(raw, fallback, min = 1) {
|
|
14
9
|
return parseNumberWithDefault(raw, fallback, { integer: true, min });
|
|
15
10
|
}
|
|
16
|
-
function resolveSearchTokenLimits(config) {
|
|
17
|
-
const resolveLimit = (value, fallback) => {
|
|
18
|
-
if (value === void 0) return fallback;
|
|
19
|
-
if (!Number.isFinite(value) || value < 0) return fallback;
|
|
20
|
-
return Math.trunc(value);
|
|
21
|
-
};
|
|
22
|
-
return {
|
|
23
|
-
maxFieldChars: resolveLimit(config.maxFieldChars, DEFAULT_SEARCH_MAX_FIELD_CHARS),
|
|
24
|
-
maxTokensPerField: resolveLimit(config.maxTokensPerField, DEFAULT_SEARCH_MAX_TOKENS_PER_FIELD),
|
|
25
|
-
maxTokensPerRecord: resolveLimit(config.maxTokensPerRecord, DEFAULT_SEARCH_MAX_TOKENS_PER_RECORD)
|
|
26
|
-
};
|
|
27
|
-
}
|
|
28
11
|
function parseHashAlgorithm(raw) {
|
|
29
12
|
const value = (raw ?? "").trim().toLowerCase();
|
|
30
13
|
if (value === "sha1") return "sha1";
|
|
31
14
|
if (value === "md5") return "md5";
|
|
32
15
|
return "sha256";
|
|
33
16
|
}
|
|
34
|
-
function parseFieldBlocklist(raw) {
|
|
35
|
-
const global = [];
|
|
36
|
-
const byEntity = /* @__PURE__ */ new Map();
|
|
37
|
-
for (const rawEntry of parseCommaSeparatedList(raw)) {
|
|
38
|
-
const entry = rawEntry.toLowerCase();
|
|
39
|
-
const separatorIndex = entry.indexOf(ENTITY_BLOCKLIST_SEPARATOR);
|
|
40
|
-
const entityType = separatorIndex >= 0 ? entry.slice(0, separatorIndex).trim() : "";
|
|
41
|
-
const field = separatorIndex >= 0 ? entry.slice(separatorIndex + 1).trim() : entry;
|
|
42
|
-
if (!field.length) continue;
|
|
43
|
-
if (!entityType.length) {
|
|
44
|
-
if (!global.includes(field)) global.push(field);
|
|
45
|
-
continue;
|
|
46
|
-
}
|
|
47
|
-
const scoped = byEntity.get(entityType) ?? [];
|
|
48
|
-
if (!scoped.includes(field)) scoped.push(field);
|
|
49
|
-
byEntity.set(entityType, scoped);
|
|
50
|
-
}
|
|
51
|
-
for (const fallback of DEFAULT_BLOCKLIST) {
|
|
52
|
-
if (!global.includes(fallback)) global.push(fallback);
|
|
53
|
-
}
|
|
54
|
-
const scopedBlocklist = /* @__PURE__ */ Object.create(null);
|
|
55
|
-
for (const [entityType, fields] of byEntity) scopedBlocklist[entityType] = fields;
|
|
56
|
-
return { global, byEntity: scopedBlocklist };
|
|
57
|
-
}
|
|
58
17
|
function resolveSearchConfig() {
|
|
59
|
-
const blocklist = parseFieldBlocklist(process.env.OM_SEARCH_FIELD_BLOCKLIST);
|
|
60
18
|
return {
|
|
61
19
|
enabled: parseBoolean(process.env.OM_SEARCH_ENABLED, true),
|
|
62
20
|
minTokenLength: resolveSearchMinTokenLength(),
|
|
63
21
|
enablePartials: parseBoolean(process.env.OM_SEARCH_ENABLE_PARTIAL, true),
|
|
64
22
|
hashAlgorithm: parseHashAlgorithm(process.env.OM_SEARCH_HASH_ALGO),
|
|
65
23
|
storeRawTokens: parseBoolean(process.env.OM_SEARCH_STORE_RAW_TOKENS, false),
|
|
66
|
-
blocklistedFields:
|
|
67
|
-
entityBlocklistedFields: blocklist.byEntity,
|
|
68
|
-
maxFieldChars: parseNumber(process.env.OM_SEARCH_MAX_FIELD_CHARS, DEFAULT_SEARCH_MAX_FIELD_CHARS, 0),
|
|
69
|
-
maxTokensPerField: parseNumber(process.env.OM_SEARCH_MAX_TOKENS_PER_FIELD, DEFAULT_SEARCH_MAX_TOKENS_PER_FIELD, 0),
|
|
70
|
-
maxTokensPerRecord: parseNumber(process.env.OM_SEARCH_MAX_TOKENS_PER_RECORD, DEFAULT_SEARCH_MAX_TOKENS_PER_RECORD, 0)
|
|
24
|
+
blocklistedFields: (process.env.OM_SEARCH_FIELD_BLOCKLIST ?? "").split(",").map((entry) => entry.trim()).filter((entry) => entry.length > 0).filter((value, index, arr) => arr.indexOf(value) === index).map((entry) => entry.toLowerCase()).concat(DEFAULT_BLOCKLIST).filter((value, index, arr) => arr.indexOf(value) === index)
|
|
71
25
|
};
|
|
72
26
|
}
|
|
73
|
-
function isSearchFieldBlocklisted(field, entityType, config) {
|
|
74
|
-
const lower = field.toLowerCase();
|
|
75
|
-
if (config.blocklistedFields.some((blocked) => lower.includes(blocked))) return true;
|
|
76
|
-
if (!entityType) return false;
|
|
77
|
-
const scoped = config.entityBlocklistedFields?.[entityType.trim().toLowerCase()];
|
|
78
|
-
if (!Array.isArray(scoped) || !scoped.length) return false;
|
|
79
|
-
return scoped.some((blocked) => lower.includes(blocked));
|
|
80
|
-
}
|
|
81
27
|
function resolveSearchMinTokenLength() {
|
|
82
28
|
return parseNumber(process.env.OM_SEARCH_MIN_LEN, DEFAULT_SEARCH_MIN_TOKEN_LENGTH, 1);
|
|
83
29
|
}
|
|
84
30
|
export {
|
|
85
|
-
DEFAULT_SEARCH_MAX_FIELD_CHARS,
|
|
86
|
-
DEFAULT_SEARCH_MAX_TOKENS_PER_FIELD,
|
|
87
|
-
DEFAULT_SEARCH_MAX_TOKENS_PER_RECORD,
|
|
88
31
|
DEFAULT_SEARCH_MIN_TOKEN_LENGTH,
|
|
89
|
-
isSearchFieldBlocklisted,
|
|
90
32
|
resolveSearchConfig,
|
|
91
|
-
resolveSearchMinTokenLength
|
|
92
|
-
resolveSearchTokenLimits
|
|
33
|
+
resolveSearchMinTokenLength
|
|
93
34
|
};
|
|
94
35
|
//# sourceMappingURL=config.js.map
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../../src/lib/search/config.ts"],
|
|
4
|
-
"sourcesContent": ["import { parseBooleanWithDefault } from '@open-mercato/shared/lib/boolean'\nimport { parseNumberWithDefault } from '@open-mercato/shared/lib/number'\
|
|
5
|
-
"mappings": "AAAA,SAAS,+BAA+B;AACxC,SAAS,8BAA8B;
|
|
4
|
+
"sourcesContent": ["import { parseBooleanWithDefault } from '@open-mercato/shared/lib/boolean'\nimport { parseNumberWithDefault } from '@open-mercato/shared/lib/number'\n\nexport type SearchConfig = {\n enabled: boolean\n minTokenLength: number\n enablePartials: boolean\n hashAlgorithm: 'sha256' | 'sha1' | 'md5'\n storeRawTokens: boolean\n blocklistedFields: string[]\n}\n\nexport const DEFAULT_SEARCH_MIN_TOKEN_LENGTH = 3\n\nconst DEFAULT_BLOCKLIST = ['password', 'token', 'secret', 'hash']\n\nfunction parseBoolean(raw: string | undefined, fallback: boolean): boolean {\n return parseBooleanWithDefault(raw, fallback)\n}\n\nfunction parseNumber(raw: string | undefined, fallback: number, min = 1): number {\n return parseNumberWithDefault(raw, fallback, { integer: true, min })\n}\n\nfunction parseHashAlgorithm(raw: string | undefined): 'sha256' | 'sha1' | 'md5' {\n const value = (raw ?? '').trim().toLowerCase()\n if (value === 'sha1') return 'sha1'\n if (value === 'md5') return 'md5'\n return 'sha256'\n}\n\nexport function resolveSearchConfig(): SearchConfig {\n return {\n enabled: parseBoolean(process.env.OM_SEARCH_ENABLED, true),\n minTokenLength: resolveSearchMinTokenLength(),\n enablePartials: parseBoolean(process.env.OM_SEARCH_ENABLE_PARTIAL, true),\n hashAlgorithm: parseHashAlgorithm(process.env.OM_SEARCH_HASH_ALGO),\n storeRawTokens: parseBoolean(process.env.OM_SEARCH_STORE_RAW_TOKENS, false),\n blocklistedFields: (process.env.OM_SEARCH_FIELD_BLOCKLIST ?? '')\n .split(',')\n .map((entry) => entry.trim())\n .filter((entry) => entry.length > 0)\n .filter((value, index, arr) => arr.indexOf(value) === index)\n .map((entry) => entry.toLowerCase())\n .concat(DEFAULT_BLOCKLIST)\n .filter((value, index, arr) => arr.indexOf(value) === index),\n }\n}\n\n/**\n * Browser-safe accessor for the minimum search token length.\n *\n * Why: client components (e.g. global search dialog) must mirror the server-side\n * tokenizer's `minTokenLength` so the UI gates the request before hitting an\n * empty result set. Pulling the value through this single helper keeps the env\n * contract (`OM_SEARCH_MIN_LEN`) authoritative on both sides.\n *\n * How to apply: call from anywhere \u2014 server, client (when the host app exposes\n * `OM_SEARCH_MIN_LEN` through `next.config.ts`'s `env` block), or tests.\n */\nexport function resolveSearchMinTokenLength(): number {\n return parseNumber(process.env.OM_SEARCH_MIN_LEN, DEFAULT_SEARCH_MIN_TOKEN_LENGTH, 1)\n}\n"],
|
|
5
|
+
"mappings": "AAAA,SAAS,+BAA+B;AACxC,SAAS,8BAA8B;AAWhC,MAAM,kCAAkC;AAE/C,MAAM,oBAAoB,CAAC,YAAY,SAAS,UAAU,MAAM;AAEhE,SAAS,aAAa,KAAyB,UAA4B;AACzE,SAAO,wBAAwB,KAAK,QAAQ;AAC9C;AAEA,SAAS,YAAY,KAAyB,UAAkB,MAAM,GAAW;AAC/E,SAAO,uBAAuB,KAAK,UAAU,EAAE,SAAS,MAAM,IAAI,CAAC;AACrE;AAEA,SAAS,mBAAmB,KAAoD;AAC9E,QAAM,SAAS,OAAO,IAAI,KAAK,EAAE,YAAY;AAC7C,MAAI,UAAU,OAAQ,QAAO;AAC7B,MAAI,UAAU,MAAO,QAAO;AAC5B,SAAO;AACT;AAEO,SAAS,sBAAoC;AAClD,SAAO;AAAA,IACL,SAAS,aAAa,QAAQ,IAAI,mBAAmB,IAAI;AAAA,IACzD,gBAAgB,4BAA4B;AAAA,IAC5C,gBAAgB,aAAa,QAAQ,IAAI,0BAA0B,IAAI;AAAA,IACvE,eAAe,mBAAmB,QAAQ,IAAI,mBAAmB;AAAA,IACjE,gBAAgB,aAAa,QAAQ,IAAI,4BAA4B,KAAK;AAAA,IAC1E,oBAAoB,QAAQ,IAAI,6BAA6B,IAC1D,MAAM,GAAG,EACT,IAAI,CAAC,UAAU,MAAM,KAAK,CAAC,EAC3B,OAAO,CAAC,UAAU,MAAM,SAAS,CAAC,EAClC,OAAO,CAAC,OAAO,OAAO,QAAQ,IAAI,QAAQ,KAAK,MAAM,KAAK,EAC1D,IAAI,CAAC,UAAU,MAAM,YAAY,CAAC,EAClC,OAAO,iBAAiB,EACxB,OAAO,CAAC,OAAO,OAAO,QAAQ,IAAI,QAAQ,KAAK,MAAM,KAAK;AAAA,EAC/D;AACF;AAaO,SAAS,8BAAsC;AACpD,SAAO,YAAY,QAAQ,IAAI,mBAAmB,iCAAiC,CAAC;AACtF;",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|
|
@@ -1,25 +1,18 @@
|
|
|
1
1
|
import crypto from "crypto";
|
|
2
|
-
import { resolveSearchConfig
|
|
2
|
+
import { resolveSearchConfig } from "./config.js";
|
|
3
3
|
function normalizeText(text) {
|
|
4
4
|
return text.normalize("NFKD").replace(/[\u0300-\u036f]/g, "").replace(/[%_]/g, " ").toLowerCase();
|
|
5
5
|
}
|
|
6
6
|
function splitTokens(text, minLength) {
|
|
7
7
|
return normalizeText(text).split(/[^a-z0-9]+/i).filter((token) => token.length >= minLength);
|
|
8
8
|
}
|
|
9
|
-
function
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
return tokens.length < limit;
|
|
15
|
-
};
|
|
16
|
-
if (!config.enablePartials) {
|
|
17
|
-
append(token);
|
|
18
|
-
return;
|
|
19
|
-
}
|
|
20
|
-
for (let length = config.minTokenLength; length <= token.length; length += 1) {
|
|
21
|
-
if (!append(token.slice(0, length))) return;
|
|
9
|
+
function expandToken(token, config) {
|
|
10
|
+
if (!config.enablePartials) return [token];
|
|
11
|
+
const results = [];
|
|
12
|
+
for (let i = config.minTokenLength; i <= token.length; i += 1) {
|
|
13
|
+
results.push(token.slice(0, i));
|
|
22
14
|
}
|
|
15
|
+
return results;
|
|
23
16
|
}
|
|
24
17
|
function hashToken(token, config) {
|
|
25
18
|
const cfg = config ?? resolveSearchConfig();
|
|
@@ -27,15 +20,10 @@ function hashToken(token, config) {
|
|
|
27
20
|
}
|
|
28
21
|
function tokenizeText(text, config) {
|
|
29
22
|
const cfg = config ?? resolveSearchConfig();
|
|
30
|
-
const
|
|
31
|
-
const
|
|
32
|
-
const
|
|
33
|
-
const
|
|
34
|
-
const tokens = [];
|
|
35
|
-
for (const token of splitTokens(boundedText, cfg.minTokenLength)) {
|
|
36
|
-
if (tokens.length >= tokenLimit) break;
|
|
37
|
-
appendExpandedToken(token, cfg, seen, tokens, tokenLimit);
|
|
38
|
-
}
|
|
23
|
+
const baseTokens = splitTokens(text, cfg.minTokenLength);
|
|
24
|
+
const expanded = baseTokens.flatMap((token) => expandToken(token, cfg));
|
|
25
|
+
const unique = Array.from(new Set(expanded));
|
|
26
|
+
const tokens = unique.filter((token) => token.length >= cfg.minTokenLength);
|
|
39
27
|
const hashes = tokens.map((token) => hashToken(token, cfg));
|
|
40
28
|
return { tokens, hashes };
|
|
41
29
|
}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../../src/lib/search/tokenize.ts"],
|
|
4
|
-
"sourcesContent": ["import crypto from 'crypto'\nimport { resolveSearchConfig,
|
|
5
|
-
"mappings": "AAAA,OAAO,YAAY;AACnB,SAAS,
|
|
4
|
+
"sourcesContent": ["import crypto from 'crypto'\nimport { resolveSearchConfig, type SearchConfig } from './config'\n\nexport type TokenizationResult = {\n tokens: string[]\n hashes: string[]\n}\n\nfunction normalizeText(text: string): string {\n return text\n .normalize('NFKD')\n .replace(/[\\u0300-\\u036f]/g, '')\n .replace(/[%_]/g, ' ')\n .toLowerCase()\n}\n\nfunction splitTokens(text: string, minLength: number): string[] {\n return normalizeText(text)\n .split(/[^a-z0-9]+/i)\n .filter((token) => token.length >= minLength)\n}\n\nfunction expandToken(token: string, config: SearchConfig): string[] {\n if (!config.enablePartials) return [token]\n const results: string[] = []\n for (let i = config.minTokenLength; i <= token.length; i += 1) {\n results.push(token.slice(0, i))\n }\n return results\n}\n\nexport function hashToken(token: string, config?: SearchConfig): string {\n const cfg = config ?? resolveSearchConfig()\n return crypto.createHash(cfg.hashAlgorithm).update(token).digest('hex')\n}\n\nexport function tokenizeText(text: string, config?: SearchConfig): TokenizationResult {\n const cfg = config ?? resolveSearchConfig()\n const baseTokens = splitTokens(text, cfg.minTokenLength)\n const expanded = baseTokens.flatMap((token) => expandToken(token, cfg))\n const unique = Array.from(new Set(expanded))\n const tokens = unique.filter((token) => token.length >= cfg.minTokenLength)\n const hashes = tokens.map((token) => hashToken(token, cfg))\n return { tokens, hashes }\n}\n"],
|
|
5
|
+
"mappings": "AAAA,OAAO,YAAY;AACnB,SAAS,2BAA8C;AAOvD,SAAS,cAAc,MAAsB;AAC3C,SAAO,KACJ,UAAU,MAAM,EAChB,QAAQ,oBAAoB,EAAE,EAC9B,QAAQ,SAAS,GAAG,EACpB,YAAY;AACjB;AAEA,SAAS,YAAY,MAAc,WAA6B;AAC9D,SAAO,cAAc,IAAI,EACtB,MAAM,aAAa,EACnB,OAAO,CAAC,UAAU,MAAM,UAAU,SAAS;AAChD;AAEA,SAAS,YAAY,OAAe,QAAgC;AAClE,MAAI,CAAC,OAAO,eAAgB,QAAO,CAAC,KAAK;AACzC,QAAM,UAAoB,CAAC;AAC3B,WAAS,IAAI,OAAO,gBAAgB,KAAK,MAAM,QAAQ,KAAK,GAAG;AAC7D,YAAQ,KAAK,MAAM,MAAM,GAAG,CAAC,CAAC;AAAA,EAChC;AACA,SAAO;AACT;AAEO,SAAS,UAAU,OAAe,QAA+B;AACtE,QAAM,MAAM,UAAU,oBAAoB;AAC1C,SAAO,OAAO,WAAW,IAAI,aAAa,EAAE,OAAO,KAAK,EAAE,OAAO,KAAK;AACxE;AAEO,SAAS,aAAa,MAAc,QAA2C;AACpF,QAAM,MAAM,UAAU,oBAAoB;AAC1C,QAAM,aAAa,YAAY,MAAM,IAAI,cAAc;AACvD,QAAM,WAAW,WAAW,QAAQ,CAAC,UAAU,YAAY,OAAO,GAAG,CAAC;AACtE,QAAM,SAAS,MAAM,KAAK,IAAI,IAAI,QAAQ,CAAC;AAC3C,QAAM,SAAS,OAAO,OAAO,CAAC,UAAU,MAAM,UAAU,IAAI,cAAc;AAC1E,QAAM,SAAS,OAAO,IAAI,CAAC,UAAU,UAAU,OAAO,GAAG,CAAC;AAC1D,SAAO,EAAE,QAAQ,OAAO;AAC1B;",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|
package/dist/lib/version.js
CHANGED
package/dist/lib/version.js.map
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../src/lib/version.ts"],
|
|
4
|
-
"sourcesContent": ["// Build-time generated version\nexport const APP_VERSION = '0.6.7
|
|
4
|
+
"sourcesContent": ["// Build-time generated version\nexport const APP_VERSION = '0.6.7'\nexport const appVersion = APP_VERSION\n"],
|
|
5
5
|
"mappings": "AACO,MAAM,cAAc;AACpB,MAAM,aAAa;",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|
|
@@ -1,24 +1,12 @@
|
|
|
1
1
|
import { signWebhookPayload, buildWebhookHeaders, generateMessageId } from "./sign.js";
|
|
2
|
-
import {
|
|
2
|
+
import { verifyWebhookSignature } from "./verify.js";
|
|
3
3
|
import { generateWebhookSecret, parseWebhookSecret, isValidWebhookSecret } from "./secrets.js";
|
|
4
|
-
import {
|
|
5
|
-
DEFAULT_WEBHOOK_BODY_LIMIT_BYTES,
|
|
6
|
-
readBoundedRequestBody,
|
|
7
|
-
resolveWebhookBodyLimitBytes,
|
|
8
|
-
WebhookBodyTooLargeError
|
|
9
|
-
} from "./body.js";
|
|
10
4
|
export {
|
|
11
|
-
DEFAULT_WEBHOOK_BODY_LIMIT_BYTES,
|
|
12
|
-
WEBHOOK_SIGNATURE_TOLERANCE_SECONDS,
|
|
13
|
-
WebhookBodyTooLargeError,
|
|
14
5
|
buildWebhookHeaders,
|
|
15
6
|
generateMessageId,
|
|
16
7
|
generateWebhookSecret,
|
|
17
8
|
isValidWebhookSecret,
|
|
18
|
-
isWebhookTimestampWithinTolerance,
|
|
19
9
|
parseWebhookSecret,
|
|
20
|
-
readBoundedRequestBody,
|
|
21
|
-
resolveWebhookBodyLimitBytes,
|
|
22
10
|
signWebhookPayload,
|
|
23
11
|
verifyWebhookSignature
|
|
24
12
|
};
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../../src/lib/webhooks/index.ts"],
|
|
4
|
-
"sourcesContent": ["export { signWebhookPayload, buildWebhookHeaders, generateMessageId } from './sign'\nexport {
|
|
5
|
-
"mappings": "AAAA,SAAS,oBAAoB,qBAAqB,yBAAyB;AAC3E,SAAS,
|
|
4
|
+
"sourcesContent": ["export { signWebhookPayload, buildWebhookHeaders, generateMessageId } from './sign'\nexport { verifyWebhookSignature } from './verify'\nexport { generateWebhookSecret, parseWebhookSecret, isValidWebhookSecret } from './secrets'\nexport type { StandardWebhookHeaders, WebhookSigningKey, WebhookVerificationResult, StandardWebhookPayload } from './types'\n"],
|
|
5
|
+
"mappings": "AAAA,SAAS,oBAAoB,qBAAqB,yBAAyB;AAC3E,SAAS,8BAA8B;AACvC,SAAS,uBAAuB,oBAAoB,4BAA4B;",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|
|
@@ -1,16 +1,13 @@
|
|
|
1
1
|
import { timingSafeEqual, createHmac } from "node:crypto";
|
|
2
2
|
import { parseWebhookSecret } from "./secrets.js";
|
|
3
|
-
const
|
|
4
|
-
function
|
|
5
|
-
const
|
|
6
|
-
if (
|
|
7
|
-
return false;
|
|
3
|
+
const TOLERANCE_SECONDS = 5 * 60;
|
|
4
|
+
function verifyWebhookSignature(msgId, timestamp, body, signatureHeader, secrets, toleranceSeconds = TOLERANCE_SECONDS) {
|
|
5
|
+
const timestampNum = parseInt(timestamp, 10);
|
|
6
|
+
if (isNaN(timestampNum)) {
|
|
7
|
+
return { valid: false };
|
|
8
8
|
}
|
|
9
|
-
const
|
|
10
|
-
|
|
11
|
-
}
|
|
12
|
-
function verifyWebhookSignature(msgId, timestamp, body, signatureHeader, secrets, toleranceSeconds = WEBHOOK_SIGNATURE_TOLERANCE_SECONDS) {
|
|
13
|
-
if (!isWebhookTimestampWithinTolerance(timestamp, toleranceSeconds)) {
|
|
9
|
+
const now = Math.floor(Date.now() / 1e3);
|
|
10
|
+
if (Math.abs(now - timestampNum) > toleranceSeconds) {
|
|
14
11
|
return { valid: false };
|
|
15
12
|
}
|
|
16
13
|
const signedContent = `${msgId}.${timestamp}.${body}`;
|
|
@@ -32,8 +29,6 @@ function verifyWebhookSignature(msgId, timestamp, body, signatureHeader, secrets
|
|
|
32
29
|
return { valid: false };
|
|
33
30
|
}
|
|
34
31
|
export {
|
|
35
|
-
WEBHOOK_SIGNATURE_TOLERANCE_SECONDS,
|
|
36
|
-
isWebhookTimestampWithinTolerance,
|
|
37
32
|
verifyWebhookSignature
|
|
38
33
|
};
|
|
39
34
|
//# sourceMappingURL=verify.js.map
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../../src/lib/webhooks/verify.ts"],
|
|
4
|
-
"sourcesContent": ["import { timingSafeEqual, createHmac } from 'node:crypto'\nimport { parseWebhookSecret } from './secrets'\nimport type { WebhookVerificationResult } from './types'\n\
|
|
5
|
-
"mappings": "AAAA,SAAS,iBAAiB,kBAAkB;AAC5C,SAAS,0BAA0B;
|
|
4
|
+
"sourcesContent": ["import { timingSafeEqual, createHmac } from 'node:crypto'\nimport { parseWebhookSecret } from './secrets'\nimport type { WebhookVerificationResult } from './types'\n\nconst TOLERANCE_SECONDS = 5 * 60 // 5 minutes\n\n/**\n * Verify a Standard Webhooks signature against one or more secrets.\n * Returns verification result with which key matched.\n */\nexport function verifyWebhookSignature(\n msgId: string,\n timestamp: string,\n body: string,\n signatureHeader: string,\n secrets: string[],\n toleranceSeconds: number = TOLERANCE_SECONDS,\n): WebhookVerificationResult {\n const timestampNum = parseInt(timestamp, 10)\n if (isNaN(timestampNum)) {\n return { valid: false }\n }\n\n const now = Math.floor(Date.now() / 1000)\n if (Math.abs(now - timestampNum) > toleranceSeconds) {\n return { valid: false }\n }\n\n const signedContent = `${msgId}.${timestamp}.${body}`\n const providedSignatures = signatureHeader.split(' ')\n\n for (let keyIndex = 0; keyIndex < secrets.length; keyIndex++) {\n const key = parseWebhookSecret(secrets[keyIndex])\n const expectedSig = createHmac('sha256', key)\n .update(signedContent)\n .digest('base64')\n\n for (const sig of providedSignatures) {\n const parts = sig.split(',')\n if (parts.length !== 2 || parts[0] !== 'v1') continue\n\n const sigBytes = Buffer.from(parts[1], 'base64')\n const expectedBytes = Buffer.from(expectedSig, 'base64')\n\n if (sigBytes.length !== expectedBytes.length) continue\n\n if (timingSafeEqual(sigBytes, expectedBytes)) {\n return { valid: true, matchedKeyIndex: keyIndex }\n }\n }\n }\n\n return { valid: false }\n}\n"],
|
|
5
|
+
"mappings": "AAAA,SAAS,iBAAiB,kBAAkB;AAC5C,SAAS,0BAA0B;AAGnC,MAAM,oBAAoB,IAAI;AAMvB,SAAS,uBACd,OACA,WACA,MACA,iBACA,SACA,mBAA2B,mBACA;AAC3B,QAAM,eAAe,SAAS,WAAW,EAAE;AAC3C,MAAI,MAAM,YAAY,GAAG;AACvB,WAAO,EAAE,OAAO,MAAM;AAAA,EACxB;AAEA,QAAM,MAAM,KAAK,MAAM,KAAK,IAAI,IAAI,GAAI;AACxC,MAAI,KAAK,IAAI,MAAM,YAAY,IAAI,kBAAkB;AACnD,WAAO,EAAE,OAAO,MAAM;AAAA,EACxB;AAEA,QAAM,gBAAgB,GAAG,KAAK,IAAI,SAAS,IAAI,IAAI;AACnD,QAAM,qBAAqB,gBAAgB,MAAM,GAAG;AAEpD,WAAS,WAAW,GAAG,WAAW,QAAQ,QAAQ,YAAY;AAC5D,UAAM,MAAM,mBAAmB,QAAQ,QAAQ,CAAC;AAChD,UAAM,cAAc,WAAW,UAAU,GAAG,EACzC,OAAO,aAAa,EACpB,OAAO,QAAQ;AAElB,eAAW,OAAO,oBAAoB;AACpC,YAAM,QAAQ,IAAI,MAAM,GAAG;AAC3B,UAAI,MAAM,WAAW,KAAK,MAAM,CAAC,MAAM,KAAM;AAE7C,YAAM,WAAW,OAAO,KAAK,MAAM,CAAC,GAAG,QAAQ;AAC/C,YAAM,gBAAgB,OAAO,KAAK,aAAa,QAAQ;AAEvD,UAAI,SAAS,WAAW,cAAc,OAAQ;AAE9C,UAAI,gBAAgB,UAAU,aAAa,GAAG;AAC5C,eAAO,EAAE,OAAO,MAAM,iBAAiB,SAAS;AAAA,MAClD;AAAA,IACF;AAAA,EACF;AAEA,SAAO,EAAE,OAAO,MAAM;AACxB;",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../src/modules/analytics.ts"],
|
|
4
|
-
"sourcesContent": ["import { createLogger } from '../lib/logger'\n\nconst logger = createLogger('shared').child({ component: 'analytics-registry' })\n\nexport type AggregateFunction = 'count' | 'sum' | 'avg' | 'min' | 'max'\n\nexport type DateGranularity = 'day' | 'week' | 'month' | 'quarter' | 'year'\n\nexport type AnalyticsFieldType = 'numeric' | 'text' | 'uuid' | 'timestamp' | 'jsonb'\n\nexport type AnalyticsEntityTypeConfig = {\n tableName: string\n schema?: string\n dateField: string\n defaultScopeFields: string[]\n
|
|
5
|
-
"mappings": "AAAA,SAAS,oBAAoB;AAE7B,MAAM,SAAS,aAAa,QAAQ,EAAE,MAAM,EAAE,WAAW,qBAAqB,CAAC;
|
|
4
|
+
"sourcesContent": ["import { createLogger } from '../lib/logger'\n\nconst logger = createLogger('shared').child({ component: 'analytics-registry' })\n\nexport type AggregateFunction = 'count' | 'sum' | 'avg' | 'min' | 'max'\n\nexport type DateGranularity = 'day' | 'week' | 'month' | 'quarter' | 'year'\n\nexport type AnalyticsFieldType = 'numeric' | 'text' | 'uuid' | 'timestamp' | 'jsonb'\n\nexport type AnalyticsEntityTypeConfig = {\n tableName: string\n schema?: string\n dateField: string\n defaultScopeFields: string[]\n}\n\nexport type AnalyticsFieldMapping = {\n dbColumn: string\n type: AnalyticsFieldType\n}\n\nexport type AnalyticsLabelResolverConfig = {\n table: string\n idColumn: string\n labelColumn: string\n}\n\nexport type AnalyticsEntityConfig = {\n entityId: string\n requiredFeatures: string[]\n entityConfig: AnalyticsEntityTypeConfig\n fieldMappings: Record<string, AnalyticsFieldMapping>\n labelResolvers?: Record<string, AnalyticsLabelResolverConfig>\n}\n\nexport type AnalyticsModuleConfig = {\n entities: AnalyticsEntityConfig[]\n}\n\nlet _analyticsModuleConfigs: AnalyticsModuleConfig[] | null = null\n\nexport function registerAnalyticsModuleConfigs(configs: AnalyticsModuleConfig[]): void {\n if (_analyticsModuleConfigs !== null && process.env.NODE_ENV === 'development') {\n logger.debug('Analytics module configs re-registered (this may occur during HMR)')\n }\n _analyticsModuleConfigs = configs\n}\n\nexport function getAnalyticsModuleConfigs(): AnalyticsModuleConfig[] {\n return _analyticsModuleConfigs ?? []\n}\n\nexport function getAllAnalyticsEntityConfigs(): AnalyticsEntityConfig[] {\n const configs = getAnalyticsModuleConfigs()\n return configs.flatMap((moduleConfig) => moduleConfig.entities)\n}\n\nexport function getAnalyticsEntityConfig(entityId: string): AnalyticsEntityConfig | null {\n const entities = getAllAnalyticsEntityConfigs()\n return entities.find((e) => e.entityId === entityId) ?? null\n}\n"],
|
|
5
|
+
"mappings": "AAAA,SAAS,oBAAoB;AAE7B,MAAM,SAAS,aAAa,QAAQ,EAAE,MAAM,EAAE,WAAW,qBAAqB,CAAC;AAsC/E,IAAI,0BAA0D;AAEvD,SAAS,+BAA+B,SAAwC;AACrF,MAAI,4BAA4B,QAAQ,QAAQ,IAAI,aAAa,eAAe;AAC9E,WAAO,MAAM,oEAAoE;AAAA,EACnF;AACA,4BAA0B;AAC5B;AAEO,SAAS,4BAAqD;AACnE,SAAO,2BAA2B,CAAC;AACrC;AAEO,SAAS,+BAAwD;AACtE,QAAM,UAAU,0BAA0B;AAC1C,SAAO,QAAQ,QAAQ,CAAC,iBAAiB,aAAa,QAAQ;AAChE;AAEO,SAAS,yBAAyB,UAAgD;AACvF,QAAM,WAAW,6BAA6B;AAC9C,SAAO,SAAS,KAAK,CAAC,MAAM,EAAE,aAAa,QAAQ,KAAK;AAC1D;",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|
|
@@ -23,8 +23,7 @@ const DOMAIN_KEYS = [
|
|
|
23
23
|
"setup",
|
|
24
24
|
"acl",
|
|
25
25
|
"di",
|
|
26
|
-
"encryption"
|
|
27
|
-
"nav"
|
|
26
|
+
"encryption"
|
|
28
27
|
];
|
|
29
28
|
const TRACKING_ISSUE_HINT = "See `.ai/specs/implemented/2026-05-04-modules-ts-unified-overrides.md` and tracking issue https://github.com/open-mercato/open-mercato/issues/1787.";
|
|
30
29
|
function applyModuleOverridesFromEnabledModules(modules) {
|
|
@@ -75,33 +74,6 @@ const aclFeatureOverrideStore = { modules: {}, programmatic: {} };
|
|
|
75
74
|
const encryptionMapOverrideStore = { modules: {}, programmatic: {} };
|
|
76
75
|
const diOverrideStore = { modules: {}, programmatic: {} };
|
|
77
76
|
const setupOverridesByModule = {};
|
|
78
|
-
const GLOBAL_NAV_OVERRIDE_STATE_KEY = "__openMercatoNavOverrideState__";
|
|
79
|
-
function getNavOverrideState() {
|
|
80
|
-
const existing = globalThis[GLOBAL_NAV_OVERRIDE_STATE_KEY];
|
|
81
|
-
if (existing && typeof existing === "object") {
|
|
82
|
-
const typed = existing;
|
|
83
|
-
if ("modules" in typed && "programmatic" in typed) return typed;
|
|
84
|
-
}
|
|
85
|
-
const initial = { modules: null, programmatic: null };
|
|
86
|
-
globalThis[GLOBAL_NAV_OVERRIDE_STATE_KEY] = initial;
|
|
87
|
-
return initial;
|
|
88
|
-
}
|
|
89
|
-
function normalizeNavGroupOrder(value) {
|
|
90
|
-
if (!Array.isArray(value)) return null;
|
|
91
|
-
const ids = Array.from(
|
|
92
|
-
new Set(
|
|
93
|
-
value.filter((id) => typeof id === "string" && id.trim().length > 0).map((id) => id.trim())
|
|
94
|
-
)
|
|
95
|
-
);
|
|
96
|
-
return ids.length > 0 ? ids : null;
|
|
97
|
-
}
|
|
98
|
-
function applyNavGroupOrderOverrides(groupOrder) {
|
|
99
|
-
getNavOverrideState().programmatic = groupOrder === null ? null : normalizeNavGroupOrder(groupOrder);
|
|
100
|
-
}
|
|
101
|
-
function getNavGroupOrderOverride() {
|
|
102
|
-
const state = getNavOverrideState();
|
|
103
|
-
return state.programmatic ?? state.modules?.groupOrder ?? null;
|
|
104
|
-
}
|
|
105
77
|
function normalizeIdOverrideKey(key, label) {
|
|
106
78
|
if (typeof key !== "string") return null;
|
|
107
79
|
const trimmed = key.trim();
|
|
@@ -289,9 +261,6 @@ function resetModuleContractOverridesForTests() {
|
|
|
289
261
|
clearStore(encryptionMapOverrideStore);
|
|
290
262
|
clearStore(diOverrideStore);
|
|
291
263
|
for (const key of Object.keys(setupOverridesByModule)) delete setupOverridesByModule[key];
|
|
292
|
-
const navState = getNavOverrideState();
|
|
293
|
-
navState.modules = null;
|
|
294
|
-
navState.programmatic = null;
|
|
295
264
|
}
|
|
296
265
|
function composeApiRouteOverrides() {
|
|
297
266
|
const modulesKeys = Object.keys(modulesConfigApiRouteOverrides);
|
|
@@ -858,23 +827,7 @@ function encryptionOverridesApplier(entries) {
|
|
|
858
827
|
applyStoreOverrides(encryptionMapOverrideStore, "modules", entry.overrides?.maps, { label: "encryption.maps" });
|
|
859
828
|
}
|
|
860
829
|
}
|
|
861
|
-
function navOverridesApplier(entries) {
|
|
862
|
-
const state = getNavOverrideState();
|
|
863
|
-
for (const entry of entries) {
|
|
864
|
-
const groupOrder = normalizeNavGroupOrder(entry.overrides?.groupOrder);
|
|
865
|
-
if (!groupOrder) continue;
|
|
866
|
-
if (state.modules && state.modules.moduleId !== entry.moduleId) {
|
|
867
|
-
logger.warn("nav.groupOrder declared by more than one module \u2014 the later one wins", {
|
|
868
|
-
previousModuleId: state.modules.moduleId,
|
|
869
|
-
moduleId: entry.moduleId,
|
|
870
|
-
hint: "Sidebar group ordering is a single app-wide decision; declare it on one module entry."
|
|
871
|
-
});
|
|
872
|
-
}
|
|
873
|
-
state.modules = { moduleId: entry.moduleId, groupOrder };
|
|
874
|
-
}
|
|
875
|
-
}
|
|
876
830
|
function registerBuiltInModuleOverrideAppliers() {
|
|
877
|
-
registerModuleOverrideApplier("nav", navOverridesApplier);
|
|
878
831
|
registerModuleOverrideApplier("routes", routesOverridesApplier);
|
|
879
832
|
registerModuleOverrideApplier("events", eventsOverridesApplier);
|
|
880
833
|
registerModuleOverrideApplier("workers", workersOverridesApplier);
|
|
@@ -912,7 +865,6 @@ export {
|
|
|
912
865
|
applyInjectionWidgetOverridesToTables,
|
|
913
866
|
applyModuleOverridesFromEnabledModules,
|
|
914
867
|
applyModuleOverridesToModules,
|
|
915
|
-
applyNavGroupOrderOverrides,
|
|
916
868
|
applyNotificationHandlerOverrides,
|
|
917
869
|
applyNotificationHandlerOverridesToEntries,
|
|
918
870
|
applyNotificationTypeOverrides,
|
|
@@ -943,7 +895,6 @@ export {
|
|
|
943
895
|
composeResponseEnricherOverrides,
|
|
944
896
|
composeSubscriberOverrides,
|
|
945
897
|
composeWorkerOverrides,
|
|
946
|
-
getNavGroupOrderOverride,
|
|
947
898
|
registerModuleOverrideApplier,
|
|
948
899
|
resetApiRouteOverridesForTests,
|
|
949
900
|
resetModuleContractOverridesForTests,
|