@semilayer/core 0.1.0 → 0.1.2

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/dist/index.cjs CHANGED
@@ -28,13 +28,23 @@ __export(index_exports, {
28
28
  INGEST_STATUSES: () => INGEST_STATUSES,
29
29
  KEY_PREFIXES: () => KEY_PREFIXES,
30
30
  LENS_STATUSES: () => LENS_STATUSES,
31
+ LIVE_TAIL_MODES: () => LIVE_TAIL_MODES,
31
32
  MERGE_STRATEGIES: () => MERGE_STRATEGIES,
32
33
  SOURCE_FEATURES: () => SOURCE_FEATURES,
34
+ STREAM_CLOSE_CODES: () => STREAM_CLOSE_CODES,
35
+ STREAM_ERROR_CODES: () => STREAM_ERROR_CODES,
36
+ STREAM_EVENT_KINDS: () => STREAM_EVENT_KINDS,
37
+ STREAM_FRAME_TYPES: () => STREAM_FRAME_TYPES,
38
+ STREAM_MODES: () => STREAM_MODES,
39
+ STREAM_OPS: () => STREAM_OPS,
33
40
  TRANSFORM_TYPES: () => TRANSFORM_TYPES,
34
41
  canonicalHash: () => canonicalHash,
35
42
  defineConfig: () => defineConfig,
43
+ deriveLiveTailMode: () => deriveLiveTailMode,
36
44
  getDeploymentMode: () => getDeploymentMode,
45
+ isLiveTailModeEnabled: () => isLiveTailModeEnabled,
37
46
  isSaasMode: () => isSaasMode,
47
+ isStreamingEnabled: () => isStreamingEnabled,
38
48
  mapDbTypeToFieldType: () => mapDbTypeToFieldType,
39
49
  resolveEmbeddingFieldNames: () => resolveEmbeddingFieldNames,
40
50
  resolveEmbeddingFields: () => resolveEmbeddingFields,
@@ -62,7 +72,8 @@ var INGEST_JOB_TYPES = [
62
72
  "full",
63
73
  "incremental",
64
74
  "delete",
65
- "records"
75
+ "records",
76
+ "sync"
66
77
  ];
67
78
  var LENS_STATUSES = [
68
79
  "paused",
@@ -169,14 +180,50 @@ function validateConfig(config) {
169
180
  }
170
181
  }
171
182
  if (lens.rules) {
172
- const validRuleKeys = /* @__PURE__ */ new Set([
183
+ const validAccessRuleKeys = /* @__PURE__ */ new Set([
173
184
  ...Object.keys(lens.facets ?? {}),
174
185
  "query"
175
186
  ]);
176
187
  for (const [key, rule] of Object.entries(lens.rules)) {
177
- if (!validRuleKeys.has(key)) {
188
+ if (key === "stream") {
189
+ if (rule == null) continue;
190
+ if (typeof rule !== "object" || Array.isArray(rule)) {
191
+ throw new Error(
192
+ `lens "${lensName}" rule "stream" must be an object`
193
+ );
194
+ }
195
+ const streamRule = rule;
196
+ if (streamRule.enabled !== void 0 && typeof streamRule.enabled !== "boolean") {
197
+ throw new Error(
198
+ `lens "${lensName}" rule "stream.enabled" must be a boolean`
199
+ );
200
+ }
201
+ if (streamRule.modes !== void 0) {
202
+ if (!Array.isArray(streamRule.modes)) {
203
+ throw new Error(
204
+ `lens "${lensName}" rule "stream.modes" must be an array`
205
+ );
206
+ }
207
+ for (const mode of streamRule.modes) {
208
+ if (mode !== "chunked" && mode !== "live") {
209
+ throw new Error(
210
+ `lens "${lensName}" rule "stream.modes" contains invalid mode "${String(mode)}" (valid: chunked, live)`
211
+ );
212
+ }
213
+ }
214
+ }
215
+ if (streamRule.maxLiveSubscriptions !== void 0) {
216
+ if (typeof streamRule.maxLiveSubscriptions !== "number" || !Number.isFinite(streamRule.maxLiveSubscriptions) || streamRule.maxLiveSubscriptions < 0) {
217
+ throw new Error(
218
+ `lens "${lensName}" rule "stream.maxLiveSubscriptions" must be a non-negative number`
219
+ );
220
+ }
221
+ }
222
+ continue;
223
+ }
224
+ if (!validAccessRuleKeys.has(key)) {
178
225
  throw new Error(
179
- `lens "${lensName}" has rule for "${key}" but no matching facet (valid: ${[...validRuleKeys].join(", ")})`
226
+ `lens "${lensName}" has rule for "${key}" but no matching facet (valid: ${[...validAccessRuleKeys].join(", ")}, stream)`
180
227
  );
181
228
  }
182
229
  if (rule !== "public" && rule !== "authenticated" && typeof rule !== "function") {
@@ -394,6 +441,66 @@ function mapDbTypeToFieldType(dbType) {
394
441
  return DB_TYPE_MAP[normalized] ?? "text";
395
442
  }
396
443
 
444
+ // src/stream.ts
445
+ var STREAM_MODES = ["chunked", "live"];
446
+ var LIVE_TAIL_MODES = ["push", "polling", "unsupported"];
447
+ var STREAM_OPS = [
448
+ "search.stream",
449
+ "query.stream",
450
+ "subscribe",
451
+ "observe",
452
+ "unsubscribe"
453
+ ];
454
+ var STREAM_FRAME_TYPES = [
455
+ "row",
456
+ "done",
457
+ "error",
458
+ "event",
459
+ "ping",
460
+ "pong"
461
+ ];
462
+ var STREAM_EVENT_KINDS = ["insert", "update", "delete"];
463
+ var STREAM_ERROR_CODES = [
464
+ "rate_limited",
465
+ "forbidden",
466
+ "bad_request",
467
+ "not_found",
468
+ "internal"
469
+ ];
470
+ var STREAM_CLOSE_CODES = {
471
+ /** Normal close — client called .close() or server finished. */
472
+ normal: 1e3,
473
+ /** Server-side internal error. */
474
+ internal: 1011,
475
+ /** Auth failed during the upgrade handshake. */
476
+ authFailed: 4401,
477
+ /** Lens forbids streaming (rules.stream.enabled === false or modes[] excludes the requested mode). */
478
+ forbidden: 4403,
479
+ /** Rate-limited at handshake — over `concurrentWsConnections` for the org. */
480
+ rateLimited: 4290,
481
+ /** Mid-stream `wsRowsPerHour` quota exceeded. */
482
+ quotaExceeded: 4291
483
+ };
484
+ function isStreamingEnabled(rules) {
485
+ return rules?.stream?.enabled !== false;
486
+ }
487
+ function isLiveTailModeEnabled(rules) {
488
+ if (!isStreamingEnabled(rules)) return false;
489
+ const modes = rules?.stream?.modes;
490
+ if (modes && !modes.includes("live")) return false;
491
+ return true;
492
+ }
493
+ function deriveLiveTailMode(input) {
494
+ const streamRules = input.rules?.stream;
495
+ if (streamRules?.enabled === false) return "unsupported";
496
+ if (streamRules?.modes && !streamRules.modes.includes("live")) return "unsupported";
497
+ if (input.acceptsIngestKey) return "push";
498
+ if (input.syncInterval && input.bridgeFeatures?.includes("incremental")) {
499
+ return "polling";
500
+ }
501
+ return "unsupported";
502
+ }
503
+
397
504
  // src/deployment.ts
398
505
  function getDeploymentMode() {
399
506
  return process.env.DEPLOYMENT_MODE ?? "enterprise";
@@ -417,13 +524,23 @@ function defineConfig(config) {
417
524
  INGEST_STATUSES,
418
525
  KEY_PREFIXES,
419
526
  LENS_STATUSES,
527
+ LIVE_TAIL_MODES,
420
528
  MERGE_STRATEGIES,
421
529
  SOURCE_FEATURES,
530
+ STREAM_CLOSE_CODES,
531
+ STREAM_ERROR_CODES,
532
+ STREAM_EVENT_KINDS,
533
+ STREAM_FRAME_TYPES,
534
+ STREAM_MODES,
535
+ STREAM_OPS,
422
536
  TRANSFORM_TYPES,
423
537
  canonicalHash,
424
538
  defineConfig,
539
+ deriveLiveTailMode,
425
540
  getDeploymentMode,
541
+ isLiveTailModeEnabled,
426
542
  isSaasMode,
543
+ isStreamingEnabled,
427
544
  mapDbTypeToFieldType,
428
545
  resolveEmbeddingFieldNames,
429
546
  resolveEmbeddingFields,
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/index.ts","../src/constants.ts","../src/validate.ts","../src/mapping.ts","../src/hash.ts","../src/type-mapper.ts","../src/deployment.ts"],"sourcesContent":["import type { SemiLayerConfig } from './config.js'\r\nimport { validateConfig } from './validate.js'\r\n\r\nexport function defineConfig(config: SemiLayerConfig): SemiLayerConfig {\r\n validateConfig(config)\r\n return config\r\n}\r\n\r\nexport { validateConfig } from './validate.js'\r\n\r\nexport type {\r\n SemiLayerConfig,\r\n SourceConfig,\r\n LensConfig,\r\n FieldConfig,\r\n SearchFacetConfig,\r\n SimilarFacetConfig,\r\n DedupFacetConfig,\r\n ClassifyFacetConfig,\r\n FacetConfig,\r\n AuthConfig,\r\n JwtConfig,\r\n JwtClaims,\r\n AccessRule,\r\n AccessRuleResult,\r\n ClaimCheck,\r\n EnvironmentAuthConfig,\r\n LensRules,\r\n LensRuleKey,\r\n EmbeddingConfig,\r\n BuiltinTransform,\r\n TransformSpec,\r\n SyncInterval,\r\n} from './config.js'\r\n\r\nexport { resolveSourceColumns, resolveEmbeddingFields, resolveEmbeddingFieldNames } from './mapping.js'\r\nexport type { EmbeddingField } from './mapping.js'\r\nexport { canonicalHash } from './hash.js'\r\nexport { mapDbTypeToFieldType } from './type-mapper.js'\r\n\r\nexport type {\r\n WhereClause,\r\n OrderByClause,\r\n QueryOptions,\r\n QueryResult,\r\n} from './query.js'\r\n\r\nexport type {\r\n BridgeRow,\r\n ReadOptions,\r\n ReadResult,\r\n TargetColumnInfo,\r\n TargetSchema,\r\n Bridge,\r\n BridgeConstructor,\r\n} from './bridge.js'\r\n\r\nexport type {\r\n TransportMode,\r\n TransportOptions,\r\n} from './transport.js'\r\n\r\nexport type {\r\n IngestJobPayload,\r\n IngestJobData,\r\n IngestControl,\r\n RateLimitState,\r\n IngestErrorEntry,\r\n LensStatusInfo,\r\n QueueCounts,\r\n FailedJobInfo,\r\n} from './ingest.js'\r\n\r\nexport {\r\n FACET_NAMES,\r\n FUTURE_FACETS,\r\n FIELD_TYPES,\r\n INGEST_JOB_TYPES,\r\n LENS_STATUSES,\r\n INGEST_STATUSES,\r\n KEY_PREFIXES,\r\n DEPLOYMENT_MODES,\r\n SOURCE_FEATURES,\r\n TRANSFORM_TYPES,\r\n MERGE_STRATEGIES,\r\n} from './constants.js'\r\n\r\nexport type {\r\n FacetName,\r\n FieldType,\r\n IngestJobType,\r\n IngestStatus,\r\n LensStatus,\r\n DeploymentMode,\r\n SourceFeature,\r\n TransformType,\r\n MergeStrategy,\r\n} from './constants.js'\r\n\r\nexport type {\r\n ISODateString,\r\n Org,\r\n Project,\r\n Environment,\r\n Source,\r\n Lens,\r\n ApiKeyInfo,\r\n Member,\r\n IngestRun,\r\n Tier,\r\n TierOverride,\r\n TierSummary,\r\n AuthUser,\r\n AuthOrg,\r\n MeResponse,\r\n NewKeyPair,\r\n CreateProjectResponse,\r\n CreateEnvResponse,\r\n PushLensSummary,\r\n PushIngestJob,\r\n PushResponse,\r\n StatusEnvironment,\r\n StatusResponse,\r\n PlatformAdmin,\r\n AuditLogEntry,\r\n PlatformStats,\r\n SystemHealth,\r\n InAppNotification,\r\n NotificationPreferenceSummary,\r\n OrgListItem,\r\n OrgDetailResponse,\r\n ProjectWithEnvs,\r\n InviteInfo,\r\n DriftLensInfo,\r\n DriftResponse,\r\n EnvsResponse,\r\n ConfigExportResponse,\r\n LensComparison,\r\n LensCreateResponse,\r\n DailyMetrics,\r\n MetricPoint,\r\n BannerData,\r\n FeedbackItem,\r\n FeedbackDetail,\r\n BannedIp,\r\n BannedUser,\r\n SearchParams,\r\n SearchResult,\r\n SearchResponse,\r\n SimilarParams,\r\n SimilarResponse,\r\n QueryParams,\r\n QueryResponse,\r\n AdminUserListItem,\r\n AdminUserListResponse,\r\n AdminUserOrgMembership,\r\n AdminUserDetail,\r\n AdminAssignUserBody,\r\n PendingInvite,\r\n PendingInvitesResponse,\r\n // Step 12 — Billing\r\n BillingSnapshot,\r\n BillingPlan,\r\n UsageMetricSnapshot,\r\n BillingCycleInfo,\r\n Invoice,\r\n TierFull,\r\n TiersResponse,\r\n CheckoutRequest,\r\n BillingRedirectResponse,\r\n CancelSubscriptionRequest,\r\n AdminMrrSnapshot,\r\n AdminCashSnapshot,\r\n AdminStripeEventRow,\r\n AdminOrgUsage,\r\n AdminTopConsumerRow,\r\n AdminTopConsumersResponse,\r\n TierOverrideRequest,\r\n QuotaErrorResponse,\r\n} from './models.js'\r\n\r\nexport { getDeploymentMode, isSaasMode } from './deployment.js'\r\n","export const FACET_NAMES = [\r\n 'search',\r\n 'similar',\r\n] as const\r\n\r\nexport type FacetName = (typeof FACET_NAMES)[number]\r\n\r\n/** Facets planned for future releases. Config types exist but no runtime support yet. */\r\nexport const FUTURE_FACETS = ['dedup', 'classify'] as const\r\n\r\nexport const FIELD_TYPES = [\r\n 'text',\r\n 'number',\r\n 'boolean',\r\n 'date',\r\n 'json',\r\n 'enum',\r\n 'relation',\r\n] as const\r\n\r\nexport type FieldType = (typeof FIELD_TYPES)[number]\r\n\r\nexport const INGEST_JOB_TYPES = [\r\n 'full',\r\n 'incremental',\r\n 'delete',\r\n 'records',\r\n] as const\r\n\r\nexport type IngestJobType = (typeof INGEST_JOB_TYPES)[number]\r\n\r\nexport const LENS_STATUSES = [\r\n 'paused',\r\n 'indexing',\r\n 'ready',\r\n 'error',\r\n] as const\r\n\r\nexport type LensStatus = (typeof LENS_STATUSES)[number]\r\n\r\nexport const INGEST_STATUSES = [\r\n 'queued',\r\n 'running',\r\n 'completed',\r\n 'failed',\r\n] as const\r\n\r\nexport type IngestStatus = (typeof INGEST_STATUSES)[number]\r\n\r\nexport const KEY_PREFIXES = {\r\n serviceKey: 'sk_',\r\n publishableKey: 'pk_',\r\n ingestKey: 'ik_',\r\n} as const\r\n\r\nexport const DEPLOYMENT_MODES = ['saas', 'enterprise'] as const\r\n\r\nexport type DeploymentMode = (typeof DEPLOYMENT_MODES)[number]\r\n\r\nexport const SOURCE_FEATURES = [\r\n 'incremental',\r\n 'change-tracking',\r\n 'streaming',\r\n] as const\r\n\r\nexport type SourceFeature = (typeof SOURCE_FEATURES)[number]\r\n\r\nexport const TRANSFORM_TYPES = [\r\n 'toString',\r\n 'toNumber',\r\n 'toBoolean',\r\n 'toDate',\r\n 'round',\r\n 'trim',\r\n 'lowercase',\r\n 'uppercase',\r\n 'default',\r\n 'split',\r\n 'join',\r\n 'truncate',\r\n 'replace',\r\n 'custom',\r\n] as const\r\n\r\nexport type TransformType = (typeof TRANSFORM_TYPES)[number]\r\n\r\nexport const MERGE_STRATEGIES = ['concat', 'coalesce'] as const\r\n\r\nexport type MergeStrategy = (typeof MERGE_STRATEGIES)[number]\r\n","import type {\n SemiLayerConfig,\n FieldConfig,\n BuiltinTransform,\n TransformSpec,\n} from './config.js'\nimport { FACET_NAMES, TRANSFORM_TYPES } from './constants.js'\n\nexport function validateConfig(config: SemiLayerConfig): void {\n if (!config.stack || typeof config.stack !== 'string') {\n throw new Error('config.stack must be a non-empty string')\n }\n\n const sourceNames = Object.keys(config.sources)\n if (sourceNames.length === 0) {\n throw new Error('config.sources must define at least one source')\n }\n\n const lensEntries = Object.entries(config.lenses)\n if (lensEntries.length === 0) {\n throw new Error('config.lenses must define at least one lens')\n }\n\n for (const [lensName, lens] of lensEntries) {\n if (!sourceNames.includes(lens.source)) {\n throw new Error(\n `lens \"${lensName}\" references unknown source \"${lens.source}\"`,\n )\n }\n\n const fieldEntries = Object.entries(lens.fields)\n const fieldNames = fieldEntries.map(([name]) => name)\n\n // ── Primary key resolution ─────────────────────────────────\n if (lens.primaryKey) {\n if (!fieldNames.includes(lens.primaryKey)) {\n throw new Error(\n `lens \"${lensName}\" primaryKey \"${lens.primaryKey}\" does not exist in fields`,\n )\n }\n const pkInFields = fieldEntries.filter(([, f]) => f.primaryKey)\n const firstPk = pkInFields[0]\n if (firstPk && firstPk[0] !== lens.primaryKey) {\n throw new Error(\n `lens \"${lensName}\" has primaryKey \"${lens.primaryKey}\" but field \"${firstPk[0]}\" also has primaryKey: true`,\n )\n }\n } else {\n const primaryKeys = fieldEntries.filter(([, f]) => f.primaryKey)\n if (primaryKeys.length !== 1) {\n throw new Error(\n `lens \"${lensName}\" must have exactly one primary key field (found ${primaryKeys.length})`,\n )\n }\n }\n\n // ── Field validation (type-specific + mapping props) ──────\n for (const [fieldName, field] of fieldEntries) {\n if (field.type === 'enum' && (!field.values || field.values.length === 0)) {\n throw new Error(\n `field \"${fieldName}\" in lens \"${lensName}\" is type \"enum\" but has no values`,\n )\n }\n if (field.type === 'relation' && !field.to) {\n throw new Error(\n `field \"${fieldName}\" in lens \"${lensName}\" is type \"relation\" but has no \"to\"`,\n )\n }\n\n // Mapping validation — inline\n validateFieldMapping(lensName, fieldName, field)\n }\n\n // ── Sync interval validation ─────────────────────────────────\n if (lens.syncInterval) {\n const valid = ['1m', '5m', '15m', '30m', '1h', '6h', '24h']\n if (!valid.includes(lens.syncInterval)) {\n throw new Error(\n `lens \"${lensName}\" syncInterval \"${lens.syncInterval}\" is invalid (valid: ${valid.join(', ')})`,\n )\n }\n }\n\n // ── Rules validation ───────────────────────────────────────\n if (lens.rules) {\n const validRuleKeys = new Set<string>([\n ...Object.keys(lens.facets ?? {}),\n 'query',\n ])\n\n for (const [key, rule] of Object.entries(lens.rules)) {\n if (!validRuleKeys.has(key)) {\n throw new Error(\n `lens \"${lensName}\" has rule for \"${key}\" but no matching facet (valid: ${[...validRuleKeys].join(', ')})`,\n )\n }\n\n if (rule !== 'public' && rule !== 'authenticated' && typeof rule !== 'function') {\n throw new Error(\n `lens \"${lensName}\" rule \"${key}\" must be 'public', 'authenticated', or a function`,\n )\n }\n }\n }\n\n // ── Facet validation (directly against field keys) ─────────\n for (const [facetName, facet] of Object.entries(lens.facets)) {\n if (!FACET_NAMES.includes(facetName as never)) {\n throw new Error(\n `lens \"${lensName}\" has invalid facet name \"${facetName}\" (valid: ${FACET_NAMES.join(', ')})`,\n )\n }\n\n if ('fields' in facet && Array.isArray(facet.fields)) {\n for (const ref of facet.fields) {\n if (!fieldNames.includes(ref)) {\n throw new Error(\n `facet \"${facetName}\" in lens \"${lensName}\" references unknown field \"${ref}\"`,\n )\n }\n }\n }\n }\n }\n}\n\n// ---------------------------------------------------------------------------\n// Field mapping validation\n// ---------------------------------------------------------------------------\n\nfunction validateFieldMapping(\n lensName: string,\n fieldName: string,\n field: FieldConfig,\n): void {\n if (field.from === undefined) return // identity mapping, nothing to validate\n\n if (Array.isArray(field.from)) {\n // Multi-source\n if (!field.merge) {\n throw new Error(\n `field \"${fieldName}\" in lens \"${lensName}\" has multiple sources but no merge strategy`,\n )\n }\n if (field.merge === 'concat' && field.separator === undefined) {\n throw new Error(\n `field \"${fieldName}\" in lens \"${lensName}\" uses merge \"concat\" but has no separator`,\n )\n }\n if (field.from.length < 2) {\n throw new Error(\n `field \"${fieldName}\" in lens \"${lensName}\" has multi-source from but fewer than 2 entries`,\n )\n }\n } else if (typeof field.from !== 'string') {\n throw new Error(\n `field \"${fieldName}\" in lens \"${lensName}\" has invalid from value (must be string or string[])`,\n )\n }\n\n if (field.transform) {\n validateTransformSpec(lensName, fieldName, field.transform)\n }\n}\n\nfunction validateTransformSpec(lensName: string, fieldName: string, spec: TransformSpec): void {\n const transforms = Array.isArray(spec) ? spec : [spec]\n for (const t of transforms) {\n if (!t || typeof t !== 'object' || !('type' in t)) {\n throw new Error(\n `field \"${fieldName}\" in lens \"${lensName}\" has invalid transform (missing type)`,\n )\n }\n if (!TRANSFORM_TYPES.includes(t.type as never)) {\n throw new Error(\n `field \"${fieldName}\" in lens \"${lensName}\" has unknown transform type \"${t.type}\"`,\n )\n }\n validateTransformFields(lensName, fieldName, t)\n }\n}\n\nfunction validateTransformFields(lensName: string, fieldName: string, t: BuiltinTransform): void {\n switch (t.type) {\n case 'split':\n if (typeof t.separator !== 'string') {\n throw new Error(\n `field \"${fieldName}\" in lens \"${lensName}\" transform \"split\" requires \"separator\"`,\n )\n }\n break\n case 'join':\n if (typeof t.separator !== 'string') {\n throw new Error(\n `field \"${fieldName}\" in lens \"${lensName}\" transform \"join\" requires \"separator\"`,\n )\n }\n break\n case 'truncate':\n if (typeof t.length !== 'number' || t.length < 0) {\n throw new Error(\n `field \"${fieldName}\" in lens \"${lensName}\" transform \"truncate\" requires positive \"length\"`,\n )\n }\n break\n case 'replace':\n if (typeof t.pattern !== 'string' || typeof t.replacement !== 'string') {\n throw new Error(\n `field \"${fieldName}\" in lens \"${lensName}\" transform \"replace\" requires \"pattern\" and \"replacement\"`,\n )\n }\n break\n case 'custom':\n if (typeof t.body !== 'string') {\n throw new Error(\n `field \"${fieldName}\" in lens \"${lensName}\" transform \"custom\" requires \"body\" string`,\n )\n }\n break\n case 'round':\n if (t.mode && !['round', 'ceil', 'floor'].includes(t.mode)) {\n throw new Error(\n `field \"${fieldName}\" in lens \"${lensName}\" transform \"round\" mode must be 'round', 'ceil', or 'floor'`,\n )\n }\n break\n }\n}\n","import type { FieldConfig } from './config.js'\n\n/**\n * Returns the list of source column names that the bridge needs to read.\n * Derives from `from` properties on fields, falling back to the output field name.\n */\nexport function resolveSourceColumns(fields: Record<string, FieldConfig>): string[] {\n const cols = new Set<string>()\n for (const [outputName, config] of Object.entries(fields)) {\n if (config.from) {\n if (Array.isArray(config.from)) {\n for (const src of config.from) cols.add(src)\n } else {\n cols.add(config.from)\n }\n } else {\n cols.add(outputName)\n }\n }\n return [...cols]\n}\n\nexport interface EmbeddingField {\n field: string\n weight: number\n}\n\n/**\n * Returns the output field names that are marked for embedding,\n * with their weights. Weight controls how many times a field's text\n * is repeated in the embedding input (higher = more relevance).\n */\nexport function resolveEmbeddingFields(fields: Record<string, FieldConfig>): EmbeddingField[] {\n const result: EmbeddingField[] = []\n for (const [name, config] of Object.entries(fields)) {\n if (!config.searchable) continue\n const weight =\n typeof config.searchable === 'object'\n ? (config.searchable.weight ?? 1)\n : 1\n result.push({ field: name, weight })\n }\n return result\n}\n\n/**\n * Convenience: returns just the field names (for APIs that only need names).\n */\nexport function resolveEmbeddingFieldNames(fields: Record<string, FieldConfig>): string[] {\n return resolveEmbeddingFields(fields).map((e) => e.field)\n}\n","import { createHash } from 'node:crypto'\n\n/**\n * Creates a deterministic SHA-256 hash of any JSON-serializable value.\n * Object keys are sorted recursively to ensure determinism regardless of insertion order.\n */\nexport function canonicalHash(obj: unknown): string {\n const json = JSON.stringify(sortKeys(obj)) ?? 'null'\n const digest = createHash('sha256').update(json).digest('hex')\n return `sha256:${digest}`\n}\n\nfunction sortKeys(value: unknown): unknown {\n if (value === null || value === undefined) return value\n if (Array.isArray(value)) return value.map(sortKeys)\n if (typeof value === 'object') {\n const sorted: Record<string, unknown> = {}\n for (const key of Object.keys(value as Record<string, unknown>).sort()) {\n sorted[key] = sortKeys((value as Record<string, unknown>)[key])\n }\n return sorted\n }\n return value\n}\n","import type { FieldType } from './constants.js'\n\nconst DB_TYPE_MAP: Record<string, FieldType> = {\n // Text\n varchar: 'text',\n text: 'text',\n char: 'text',\n 'character varying': 'text',\n character: 'text',\n citext: 'text',\n uuid: 'text',\n name: 'text',\n\n // Number\n integer: 'number',\n int: 'number',\n int4: 'number',\n bigint: 'number',\n int8: 'number',\n smallint: 'number',\n int2: 'number',\n numeric: 'number',\n decimal: 'number',\n real: 'number',\n float4: 'number',\n 'double precision': 'number',\n float8: 'number',\n serial: 'number',\n bigserial: 'number',\n\n // Boolean\n boolean: 'boolean',\n bool: 'boolean',\n\n // Date\n timestamp: 'date',\n 'timestamp with time zone': 'date',\n 'timestamp without time zone': 'date',\n timestamptz: 'date',\n date: 'date',\n time: 'date',\n 'time with time zone': 'date',\n 'time without time zone': 'date',\n timetz: 'date',\n\n // JSON\n json: 'json',\n jsonb: 'json',\n\n // Arrays → json\n 'ARRAY': 'json',\n}\n\n/**\n * Maps a raw database column type to a SemiLayer FieldType.\n * Falls back to 'text' for unknown types.\n */\nexport function mapDbTypeToFieldType(dbType: string): FieldType {\n const normalized = dbType.toLowerCase().trim()\n return DB_TYPE_MAP[normalized] ?? 'text'\n}\n","import type { DeploymentMode } from './constants.js'\r\n\r\nexport function getDeploymentMode(): DeploymentMode {\r\n return (process.env.DEPLOYMENT_MODE as DeploymentMode) ?? 'enterprise'\r\n}\r\n\r\nexport function isSaasMode(): boolean {\r\n return getDeploymentMode() === 'saas'\r\n}\r\n"],"mappings":"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","names":[]}
1
+ {"version":3,"sources":["../src/index.ts","../src/constants.ts","../src/validate.ts","../src/mapping.ts","../src/hash.ts","../src/type-mapper.ts","../src/stream.ts","../src/deployment.ts"],"sourcesContent":["import type { SemiLayerConfig } from './config.js'\nimport { validateConfig } from './validate.js'\n\nexport function defineConfig(config: SemiLayerConfig): SemiLayerConfig {\n validateConfig(config)\n return config\n}\n\nexport { validateConfig } from './validate.js'\n\nexport type {\n SemiLayerConfig,\n SourceConfig,\n LensConfig,\n FieldConfig,\n SearchFacetConfig,\n SimilarFacetConfig,\n DedupFacetConfig,\n ClassifyFacetConfig,\n FacetConfig,\n AuthConfig,\n JwtConfig,\n JwtClaims,\n AccessRule,\n AccessRuleResult,\n ClaimCheck,\n EnvironmentAuthConfig,\n LensRules,\n LensRuleKey,\n StreamRules,\n EmbeddingConfig,\n BuiltinTransform,\n TransformSpec,\n SyncInterval,\n} from './config.js'\n\nexport { resolveSourceColumns, resolveEmbeddingFields, resolveEmbeddingFieldNames } from './mapping.js'\nexport type { EmbeddingField } from './mapping.js'\nexport { canonicalHash } from './hash.js'\nexport { mapDbTypeToFieldType } from './type-mapper.js'\n\nexport type {\n WhereClause,\n OrderByClause,\n QueryOptions,\n QueryResult,\n} from './query.js'\n\nexport type {\n BridgeRow,\n ReadOptions,\n ReadResult,\n TargetColumnInfo,\n TargetSchema,\n Bridge,\n BridgeConstructor,\n} from './bridge.js'\n\nexport type {\n TransportMode,\n TransportOptions,\n} from './transport.js'\n\nexport {\n STREAM_MODES,\n LIVE_TAIL_MODES,\n STREAM_OPS,\n STREAM_FRAME_TYPES,\n STREAM_EVENT_KINDS,\n STREAM_ERROR_CODES,\n STREAM_CLOSE_CODES,\n deriveLiveTailMode,\n isStreamingEnabled,\n isLiveTailModeEnabled,\n} from './stream.js'\n\nexport type {\n StreamMode,\n LiveTailMode,\n StreamOp,\n StreamFrameType,\n StreamEventKind,\n StreamErrorCode,\n StreamCloseCode,\n StreamSearchParams,\n StreamQueryParams,\n SubscribeParams,\n StreamOpFrame,\n StreamMeta,\n StreamRowFrame,\n StreamDoneFrame,\n StreamEventFrame,\n StreamErrorFrame,\n StreamPingFrame,\n StreamPongFrame,\n StreamFrame,\n StreamEvent,\n StreamSearchRow,\n DeriveLiveTailModeInput,\n} from './stream.js'\n\nexport type {\n IngestJobPayload,\n IngestJobData,\n IngestControl,\n RateLimitState,\n IngestErrorEntry,\n LensStatusInfo,\n QueueCounts,\n FailedJobInfo,\n} from './ingest.js'\n\nexport {\n FACET_NAMES,\n FUTURE_FACETS,\n FIELD_TYPES,\n INGEST_JOB_TYPES,\n LENS_STATUSES,\n INGEST_STATUSES,\n KEY_PREFIXES,\n DEPLOYMENT_MODES,\n SOURCE_FEATURES,\n TRANSFORM_TYPES,\n MERGE_STRATEGIES,\n} from './constants.js'\n\nexport type {\n FacetName,\n FieldType,\n IngestJobType,\n IngestStatus,\n LensStatus,\n DeploymentMode,\n SourceFeature,\n TransformType,\n MergeStrategy,\n} from './constants.js'\n\nexport type {\n ISODateString,\n Org,\n Project,\n Environment,\n Source,\n Lens,\n ApiKeyInfo,\n Member,\n IngestRun,\n Page,\n Tier,\n TierOverride,\n TierSummary,\n AuthUser,\n AuthOrg,\n MeResponse,\n NewKeyPair,\n CreateProjectResponse,\n CreateEnvResponse,\n PushLensSummary,\n PushIngestJob,\n PushResponse,\n StatusEnvironment,\n StatusResponse,\n PlatformAdmin,\n AuditLogEntry,\n PlatformStats,\n SystemHealth,\n InAppNotification,\n NotificationPreferenceSummary,\n OrgListItem,\n OrgDetailResponse,\n ProjectWithEnvs,\n InviteInfo,\n DriftLensInfo,\n DriftResponse,\n EnvsResponse,\n ConfigExportResponse,\n LensComparison,\n LensCreateResponse,\n DailyMetrics,\n MetricPoint,\n BannerData,\n FeedbackItem,\n FeedbackDetail,\n BannedIp,\n BannedUser,\n SearchParams,\n SearchResult,\n SearchResponse,\n SimilarParams,\n SimilarResponse,\n QueryParams,\n QueryResponse,\n AdminUserListItem,\n AdminUserListResponse,\n AdminUserOrgMembership,\n AdminUserDetail,\n AdminAssignUserBody,\n PendingInvite,\n PendingInvitesResponse,\n // Step 12 — Billing\n BillingSnapshot,\n BillingPlan,\n UsageMetricSnapshot,\n BillingCycleInfo,\n Invoice,\n TierFull,\n TiersResponse,\n CheckoutRequest,\n BillingRedirectResponse,\n CancelSubscriptionRequest,\n AdminMrrSnapshot,\n AdminCashSnapshot,\n AdminStripeEventRow,\n AdminOrgUsage,\n AdminTopConsumerRow,\n AdminTopConsumersResponse,\n TierOverrideRequest,\n QuotaErrorResponse,\n} from './models.js'\n\nexport { getDeploymentMode, isSaasMode } from './deployment.js'\n","export const FACET_NAMES = [\n 'search',\n 'similar',\n] as const\n\nexport type FacetName = (typeof FACET_NAMES)[number]\n\n/** Facets planned for future releases. Config types exist but no runtime support yet. */\nexport const FUTURE_FACETS = ['dedup', 'classify'] as const\n\nexport const FIELD_TYPES = [\n 'text',\n 'number',\n 'boolean',\n 'date',\n 'json',\n 'enum',\n 'relation',\n] as const\n\nexport type FieldType = (typeof FIELD_TYPES)[number]\n\nexport const INGEST_JOB_TYPES = [\n 'full',\n 'incremental',\n 'delete',\n 'records',\n 'sync',\n] as const\n\nexport type IngestJobType = (typeof INGEST_JOB_TYPES)[number]\n\nexport const LENS_STATUSES = [\n 'paused',\n 'indexing',\n 'ready',\n 'error',\n] as const\n\nexport type LensStatus = (typeof LENS_STATUSES)[number]\n\nexport const INGEST_STATUSES = [\n 'queued',\n 'running',\n 'completed',\n 'failed',\n] as const\n\nexport type IngestStatus = (typeof INGEST_STATUSES)[number]\n\nexport const KEY_PREFIXES = {\n serviceKey: 'sk_',\n publishableKey: 'pk_',\n ingestKey: 'ik_',\n} as const\n\nexport const DEPLOYMENT_MODES = ['saas', 'enterprise'] as const\n\nexport type DeploymentMode = (typeof DEPLOYMENT_MODES)[number]\n\nexport const SOURCE_FEATURES = [\n 'incremental',\n 'change-tracking',\n 'streaming',\n] as const\n\nexport type SourceFeature = (typeof SOURCE_FEATURES)[number]\n\nexport const TRANSFORM_TYPES = [\n 'toString',\n 'toNumber',\n 'toBoolean',\n 'toDate',\n 'round',\n 'trim',\n 'lowercase',\n 'uppercase',\n 'default',\n 'split',\n 'join',\n 'truncate',\n 'replace',\n 'custom',\n] as const\n\nexport type TransformType = (typeof TRANSFORM_TYPES)[number]\n\nexport const MERGE_STRATEGIES = ['concat', 'coalesce'] as const\n\nexport type MergeStrategy = (typeof MERGE_STRATEGIES)[number]\n","import type {\n SemiLayerConfig,\n FieldConfig,\n BuiltinTransform,\n TransformSpec,\n} from './config.js'\nimport { FACET_NAMES, TRANSFORM_TYPES } from './constants.js'\n\nexport function validateConfig(config: SemiLayerConfig): void {\n if (!config.stack || typeof config.stack !== 'string') {\n throw new Error('config.stack must be a non-empty string')\n }\n\n const sourceNames = Object.keys(config.sources)\n if (sourceNames.length === 0) {\n throw new Error('config.sources must define at least one source')\n }\n\n const lensEntries = Object.entries(config.lenses)\n if (lensEntries.length === 0) {\n throw new Error('config.lenses must define at least one lens')\n }\n\n for (const [lensName, lens] of lensEntries) {\n if (!sourceNames.includes(lens.source)) {\n throw new Error(\n `lens \"${lensName}\" references unknown source \"${lens.source}\"`,\n )\n }\n\n const fieldEntries = Object.entries(lens.fields)\n const fieldNames = fieldEntries.map(([name]) => name)\n\n // ── Primary key resolution ─────────────────────────────────\n if (lens.primaryKey) {\n if (!fieldNames.includes(lens.primaryKey)) {\n throw new Error(\n `lens \"${lensName}\" primaryKey \"${lens.primaryKey}\" does not exist in fields`,\n )\n }\n const pkInFields = fieldEntries.filter(([, f]) => f.primaryKey)\n const firstPk = pkInFields[0]\n if (firstPk && firstPk[0] !== lens.primaryKey) {\n throw new Error(\n `lens \"${lensName}\" has primaryKey \"${lens.primaryKey}\" but field \"${firstPk[0]}\" also has primaryKey: true`,\n )\n }\n } else {\n const primaryKeys = fieldEntries.filter(([, f]) => f.primaryKey)\n if (primaryKeys.length !== 1) {\n throw new Error(\n `lens \"${lensName}\" must have exactly one primary key field (found ${primaryKeys.length})`,\n )\n }\n }\n\n // ── Field validation (type-specific + mapping props) ──────\n for (const [fieldName, field] of fieldEntries) {\n if (field.type === 'enum' && (!field.values || field.values.length === 0)) {\n throw new Error(\n `field \"${fieldName}\" in lens \"${lensName}\" is type \"enum\" but has no values`,\n )\n }\n if (field.type === 'relation' && !field.to) {\n throw new Error(\n `field \"${fieldName}\" in lens \"${lensName}\" is type \"relation\" but has no \"to\"`,\n )\n }\n\n // Mapping validation — inline\n validateFieldMapping(lensName, fieldName, field)\n }\n\n // ── Sync interval validation ─────────────────────────────────\n if (lens.syncInterval) {\n const valid = ['1m', '5m', '15m', '30m', '1h', '6h', '24h']\n if (!valid.includes(lens.syncInterval)) {\n throw new Error(\n `lens \"${lensName}\" syncInterval \"${lens.syncInterval}\" is invalid (valid: ${valid.join(', ')})`,\n )\n }\n }\n\n // ── Rules validation ───────────────────────────────────────\n if (lens.rules) {\n const validAccessRuleKeys = new Set<string>([\n ...Object.keys(lens.facets ?? {}),\n 'query',\n ])\n\n for (const [key, rule] of Object.entries(lens.rules)) {\n // `stream` is a transport, not an access rule — it has its own shape.\n if (key === 'stream') {\n if (rule == null) continue\n if (typeof rule !== 'object' || Array.isArray(rule)) {\n throw new Error(\n `lens \"${lensName}\" rule \"stream\" must be an object`,\n )\n }\n const streamRule = rule as { enabled?: unknown; modes?: unknown; maxLiveSubscriptions?: unknown }\n if (streamRule.enabled !== undefined && typeof streamRule.enabled !== 'boolean') {\n throw new Error(\n `lens \"${lensName}\" rule \"stream.enabled\" must be a boolean`,\n )\n }\n if (streamRule.modes !== undefined) {\n if (!Array.isArray(streamRule.modes)) {\n throw new Error(\n `lens \"${lensName}\" rule \"stream.modes\" must be an array`,\n )\n }\n for (const mode of streamRule.modes) {\n if (mode !== 'chunked' && mode !== 'live') {\n throw new Error(\n `lens \"${lensName}\" rule \"stream.modes\" contains invalid mode \"${String(mode)}\" (valid: chunked, live)`,\n )\n }\n }\n }\n if (streamRule.maxLiveSubscriptions !== undefined) {\n if (\n typeof streamRule.maxLiveSubscriptions !== 'number' ||\n !Number.isFinite(streamRule.maxLiveSubscriptions) ||\n streamRule.maxLiveSubscriptions < 0\n ) {\n throw new Error(\n `lens \"${lensName}\" rule \"stream.maxLiveSubscriptions\" must be a non-negative number`,\n )\n }\n }\n continue\n }\n\n if (!validAccessRuleKeys.has(key)) {\n throw new Error(\n `lens \"${lensName}\" has rule for \"${key}\" but no matching facet (valid: ${[...validAccessRuleKeys].join(', ')}, stream)`,\n )\n }\n\n if (rule !== 'public' && rule !== 'authenticated' && typeof rule !== 'function') {\n throw new Error(\n `lens \"${lensName}\" rule \"${key}\" must be 'public', 'authenticated', or a function`,\n )\n }\n }\n }\n\n // ── Facet validation (directly against field keys) ─────────\n for (const [facetName, facet] of Object.entries(lens.facets)) {\n if (!FACET_NAMES.includes(facetName as never)) {\n throw new Error(\n `lens \"${lensName}\" has invalid facet name \"${facetName}\" (valid: ${FACET_NAMES.join(', ')})`,\n )\n }\n\n if ('fields' in facet && Array.isArray(facet.fields)) {\n for (const ref of facet.fields) {\n if (!fieldNames.includes(ref)) {\n throw new Error(\n `facet \"${facetName}\" in lens \"${lensName}\" references unknown field \"${ref}\"`,\n )\n }\n }\n }\n }\n }\n}\n\n// ---------------------------------------------------------------------------\n// Field mapping validation\n// ---------------------------------------------------------------------------\n\nfunction validateFieldMapping(\n lensName: string,\n fieldName: string,\n field: FieldConfig,\n): void {\n if (field.from === undefined) return // identity mapping, nothing to validate\n\n if (Array.isArray(field.from)) {\n // Multi-source\n if (!field.merge) {\n throw new Error(\n `field \"${fieldName}\" in lens \"${lensName}\" has multiple sources but no merge strategy`,\n )\n }\n if (field.merge === 'concat' && field.separator === undefined) {\n throw new Error(\n `field \"${fieldName}\" in lens \"${lensName}\" uses merge \"concat\" but has no separator`,\n )\n }\n if (field.from.length < 2) {\n throw new Error(\n `field \"${fieldName}\" in lens \"${lensName}\" has multi-source from but fewer than 2 entries`,\n )\n }\n } else if (typeof field.from !== 'string') {\n throw new Error(\n `field \"${fieldName}\" in lens \"${lensName}\" has invalid from value (must be string or string[])`,\n )\n }\n\n if (field.transform) {\n validateTransformSpec(lensName, fieldName, field.transform)\n }\n}\n\nfunction validateTransformSpec(lensName: string, fieldName: string, spec: TransformSpec): void {\n const transforms = Array.isArray(spec) ? spec : [spec]\n for (const t of transforms) {\n if (!t || typeof t !== 'object' || !('type' in t)) {\n throw new Error(\n `field \"${fieldName}\" in lens \"${lensName}\" has invalid transform (missing type)`,\n )\n }\n if (!TRANSFORM_TYPES.includes(t.type as never)) {\n throw new Error(\n `field \"${fieldName}\" in lens \"${lensName}\" has unknown transform type \"${t.type}\"`,\n )\n }\n validateTransformFields(lensName, fieldName, t)\n }\n}\n\nfunction validateTransformFields(lensName: string, fieldName: string, t: BuiltinTransform): void {\n switch (t.type) {\n case 'split':\n if (typeof t.separator !== 'string') {\n throw new Error(\n `field \"${fieldName}\" in lens \"${lensName}\" transform \"split\" requires \"separator\"`,\n )\n }\n break\n case 'join':\n if (typeof t.separator !== 'string') {\n throw new Error(\n `field \"${fieldName}\" in lens \"${lensName}\" transform \"join\" requires \"separator\"`,\n )\n }\n break\n case 'truncate':\n if (typeof t.length !== 'number' || t.length < 0) {\n throw new Error(\n `field \"${fieldName}\" in lens \"${lensName}\" transform \"truncate\" requires positive \"length\"`,\n )\n }\n break\n case 'replace':\n if (typeof t.pattern !== 'string' || typeof t.replacement !== 'string') {\n throw new Error(\n `field \"${fieldName}\" in lens \"${lensName}\" transform \"replace\" requires \"pattern\" and \"replacement\"`,\n )\n }\n break\n case 'custom':\n if (typeof t.body !== 'string') {\n throw new Error(\n `field \"${fieldName}\" in lens \"${lensName}\" transform \"custom\" requires \"body\" string`,\n )\n }\n break\n case 'round':\n if (t.mode && !['round', 'ceil', 'floor'].includes(t.mode)) {\n throw new Error(\n `field \"${fieldName}\" in lens \"${lensName}\" transform \"round\" mode must be 'round', 'ceil', or 'floor'`,\n )\n }\n break\n }\n}\n","import type { FieldConfig } from './config.js'\n\n/**\n * Returns the list of source column names that the bridge needs to read.\n * Derives from `from` properties on fields, falling back to the output field name.\n */\nexport function resolveSourceColumns(fields: Record<string, FieldConfig>): string[] {\n const cols = new Set<string>()\n for (const [outputName, config] of Object.entries(fields)) {\n if (config.from) {\n if (Array.isArray(config.from)) {\n for (const src of config.from) cols.add(src)\n } else {\n cols.add(config.from)\n }\n } else {\n cols.add(outputName)\n }\n }\n return [...cols]\n}\n\nexport interface EmbeddingField {\n field: string\n weight: number\n}\n\n/**\n * Returns the output field names that are marked for embedding,\n * with their weights. Weight controls how many times a field's text\n * is repeated in the embedding input (higher = more relevance).\n */\nexport function resolveEmbeddingFields(fields: Record<string, FieldConfig>): EmbeddingField[] {\n const result: EmbeddingField[] = []\n for (const [name, config] of Object.entries(fields)) {\n if (!config.searchable) continue\n const weight =\n typeof config.searchable === 'object'\n ? (config.searchable.weight ?? 1)\n : 1\n result.push({ field: name, weight })\n }\n return result\n}\n\n/**\n * Convenience: returns just the field names (for APIs that only need names).\n */\nexport function resolveEmbeddingFieldNames(fields: Record<string, FieldConfig>): string[] {\n return resolveEmbeddingFields(fields).map((e) => e.field)\n}\n","import { createHash } from 'node:crypto'\n\n/**\n * Creates a deterministic SHA-256 hash of any JSON-serializable value.\n * Object keys are sorted recursively to ensure determinism regardless of insertion order.\n */\nexport function canonicalHash(obj: unknown): string {\n const json = JSON.stringify(sortKeys(obj)) ?? 'null'\n const digest = createHash('sha256').update(json).digest('hex')\n return `sha256:${digest}`\n}\n\nfunction sortKeys(value: unknown): unknown {\n if (value === null || value === undefined) return value\n if (Array.isArray(value)) return value.map(sortKeys)\n if (typeof value === 'object') {\n const sorted: Record<string, unknown> = {}\n for (const key of Object.keys(value as Record<string, unknown>).sort()) {\n sorted[key] = sortKeys((value as Record<string, unknown>)[key])\n }\n return sorted\n }\n return value\n}\n","import type { FieldType } from './constants.js'\n\nconst DB_TYPE_MAP: Record<string, FieldType> = {\n // Text\n varchar: 'text',\n text: 'text',\n char: 'text',\n 'character varying': 'text',\n character: 'text',\n citext: 'text',\n uuid: 'text',\n name: 'text',\n\n // Number\n integer: 'number',\n int: 'number',\n int4: 'number',\n bigint: 'number',\n int8: 'number',\n smallint: 'number',\n int2: 'number',\n numeric: 'number',\n decimal: 'number',\n real: 'number',\n float4: 'number',\n 'double precision': 'number',\n float8: 'number',\n serial: 'number',\n bigserial: 'number',\n\n // Boolean\n boolean: 'boolean',\n bool: 'boolean',\n\n // Date\n timestamp: 'date',\n 'timestamp with time zone': 'date',\n 'timestamp without time zone': 'date',\n timestamptz: 'date',\n date: 'date',\n time: 'date',\n 'time with time zone': 'date',\n 'time without time zone': 'date',\n timetz: 'date',\n\n // JSON\n json: 'json',\n jsonb: 'json',\n\n // Arrays → json\n 'ARRAY': 'json',\n}\n\n/**\n * Maps a raw database column type to a SemiLayer FieldType.\n * Falls back to 'text' for unknown types.\n */\nexport function mapDbTypeToFieldType(dbType: string): FieldType {\n const normalized = dbType.toLowerCase().trim()\n return DB_TYPE_MAP[normalized] ?? 'text'\n}\n","import type { SearchResult, SearchParams, QueryParams } from './models.js'\nimport type { SourceFeature } from './constants.js'\nimport type { LensRules, SyncInterval } from './config.js'\n\n// ---------------------------------------------------------------------------\n// Constants\n// ---------------------------------------------------------------------------\n\nexport const STREAM_MODES = ['chunked', 'live'] as const\nexport type StreamMode = (typeof STREAM_MODES)[number]\n\nexport const LIVE_TAIL_MODES = ['push', 'polling', 'unsupported'] as const\nexport type LiveTailMode = (typeof LIVE_TAIL_MODES)[number]\n\n/** WebSocket op names sent from client to server in the `op` field. */\nexport const STREAM_OPS = [\n 'search.stream',\n 'query.stream',\n 'subscribe',\n 'observe',\n 'unsubscribe',\n] as const\nexport type StreamOp = (typeof STREAM_OPS)[number]\n\n/** Frame `type` values for both directions. */\nexport const STREAM_FRAME_TYPES = [\n 'row',\n 'done',\n 'error',\n 'event',\n 'ping',\n 'pong',\n] as const\nexport type StreamFrameType = (typeof STREAM_FRAME_TYPES)[number]\n\n/** Subscription event kinds (mirrors ingest write operations). */\nexport const STREAM_EVENT_KINDS = ['insert', 'update', 'delete'] as const\nexport type StreamEventKind = (typeof STREAM_EVENT_KINDS)[number]\n\n/** Error codes carried in `error` frames. */\nexport const STREAM_ERROR_CODES = [\n 'rate_limited',\n 'forbidden',\n 'bad_request',\n 'not_found',\n 'internal',\n] as const\nexport type StreamErrorCode = (typeof STREAM_ERROR_CODES)[number]\n\n/**\n * WebSocket close codes.\n *\n * Reserved codes (1xxx) follow RFC 6455. The 4xxx range is application-defined.\n */\nexport const STREAM_CLOSE_CODES = {\n /** Normal close — client called .close() or server finished. */\n normal: 1000,\n /** Server-side internal error. */\n internal: 1011,\n /** Auth failed during the upgrade handshake. */\n authFailed: 4401,\n /** Lens forbids streaming (rules.stream.enabled === false or modes[] excludes the requested mode). */\n forbidden: 4403,\n /** Rate-limited at handshake — over `concurrentWsConnections` for the org. */\n rateLimited: 4290,\n /** Mid-stream `wsRowsPerHour` quota exceeded. */\n quotaExceeded: 4291,\n} as const\n\nexport type StreamCloseCode = (typeof STREAM_CLOSE_CODES)[keyof typeof STREAM_CLOSE_CODES]\n\n// ---------------------------------------------------------------------------\n// Request shapes\n// ---------------------------------------------------------------------------\n\nexport interface StreamSearchParams extends SearchParams {\n /** Optional batch size hint — server may ignore. Default: 50. */\n batchSize?: number\n}\n\nexport interface StreamQueryParams extends QueryParams {\n /** Optional batch size hint — server may ignore. Default: 100. */\n batchSize?: number\n}\n\nexport interface SubscribeParams {\n /**\n * Optional in-process filter applied to events before they're emitted.\n * v0.1: simple equality only. Complex predicate pushdown is a v0.2 feature.\n */\n filter?: Record<string, unknown>\n}\n\n// ---------------------------------------------------------------------------\n// Op frame (client → server)\n// ---------------------------------------------------------------------------\n\n/**\n * One control frame sent from client to server. Multiple ops can ride a single\n * WebSocket connection — `id` is the multiplexing key the server echoes back\n * on response frames.\n */\nexport interface StreamOpFrame {\n id: string\n op: StreamOp\n params?: StreamSearchParams | StreamQueryParams | SubscribeParams | Record<string, unknown>\n}\n\n// ---------------------------------------------------------------------------\n// Response frames (server → client)\n// ---------------------------------------------------------------------------\n\nexport interface StreamMeta {\n count: number\n durationMs: number\n}\n\n/** A row from a chunked search/query stream. */\nexport interface StreamRowFrame<T = Record<string, unknown>> {\n id: string\n type: 'row'\n data: T\n}\n\n/** Terminal frame for a chunked op — no more rows will arrive for this id. */\nexport interface StreamDoneFrame {\n id: string\n type: 'done'\n meta: StreamMeta\n}\n\n/** Subscription event — pushed for each matching ingest write. */\nexport interface StreamEventFrame<T = Record<string, unknown>> {\n id: string\n type: 'event'\n kind: StreamEventKind\n record: T\n}\n\n/** Error attached to a specific op id (or global if id omitted). */\nexport interface StreamErrorFrame {\n id?: string\n type: 'error'\n code: StreamErrorCode\n message: string\n}\n\n/** Server heartbeat. Client must reply with a `pong` frame. */\nexport interface StreamPingFrame {\n type: 'ping'\n}\n\n/** Client heartbeat reply. */\nexport interface StreamPongFrame {\n type: 'pong'\n}\n\n/** Discriminated union of every frame the server can send. */\nexport type StreamFrame<T = Record<string, unknown>> =\n | StreamRowFrame<T>\n | StreamDoneFrame\n | StreamEventFrame<T>\n | StreamErrorFrame\n | StreamPingFrame\n | StreamPongFrame\n\n// ---------------------------------------------------------------------------\n// Public consumer types\n// ---------------------------------------------------------------------------\n\n/** What `BeamClient.subscribe()` yields per event. */\nexport interface StreamEvent<M = Record<string, unknown>> {\n kind: StreamEventKind\n record: M\n}\n\n/** What `BeamClient.streamSearch()` yields per row. */\nexport type StreamSearchRow<M = Record<string, unknown>> = SearchResult<M>\n\n// ---------------------------------------------------------------------------\n// Live tail mode derivation\n// ---------------------------------------------------------------------------\n\nexport interface DeriveLiveTailModeInput {\n /** Lens rules — if `rules.stream.modes` excludes `'live'`, the mode is `unsupported`. */\n rules?: LensRules\n /** Lens sync interval — presence implies polling-mode ingest. */\n syncInterval?: SyncInterval\n /** Source feature flags from the bridge. */\n bridgeFeatures?: SourceFeature[]\n /**\n * Whether at least one ingest key (ik_) exists for the lens. This is a\n * runtime fact (DB-derived) — callers must look it up before invoking.\n */\n acceptsIngestKey: boolean\n}\n\n/**\n * Is streaming enabled at all for this lens? Returns false only when the lens\n * config explicitly opts out via `rules.stream.enabled === false`. Default: true.\n *\n * This is the question the worker asks before populating the live tail buffer:\n * if a lens has streaming disabled, no one can subscribe, so there is no point\n * paying for the INSERT + NOTIFY.\n */\nexport function isStreamingEnabled(rules?: LensRules): boolean {\n return rules?.stream?.enabled !== false\n}\n\n/**\n * Is the `live` stream mode allowed for this lens? Returns false if streaming\n * is fully disabled OR if `rules.stream.modes` is set and excludes `'live'`.\n * Default: true.\n *\n * This is the gate for the worker's observation pathway. When false, the worker\n * skips the live tail buffer entirely — observation is microweight, but it is\n * not zero, and there is no value populating a buffer subscribers can never read.\n */\nexport function isLiveTailModeEnabled(rules?: LensRules): boolean {\n if (!isStreamingEnabled(rules)) return false\n const modes = rules?.stream?.modes\n if (modes && !modes.includes('live')) return false\n return true\n}\n\n/**\n * Derive the live-tail mode for a lens.\n *\n * Live tail rides our **own ingest write path**, not bridge-native CDC. So as\n * long as records are being written to `vectors.embeddings` by *some* ingest\n * pathway, live tail works:\n *\n * - `'push'` — the lens accepts `ik_` ingest webhooks → near-realtime fan-out\n * - `'polling'` — the bridge supports incremental sync and a syncInterval is set\n * → smooth-but-bursty fan-out at the polling cadence\n * - `'unsupported'` — neither path is available, OR `rules.stream.modes`\n * explicitly excludes `'live'`. The Console Explorer disables the live tab\n * and the `subscribe` op returns a forbidden close code.\n */\nexport function deriveLiveTailMode(input: DeriveLiveTailModeInput): LiveTailMode {\n // Explicit opt-out via lens rules\n const streamRules = input.rules?.stream\n if (streamRules?.enabled === false) return 'unsupported'\n if (streamRules?.modes && !streamRules.modes.includes('live')) return 'unsupported'\n\n // Push mode — ingest webhook key exists\n if (input.acceptsIngestKey) return 'push'\n\n // Polling mode — incremental sync configured\n if (input.syncInterval && input.bridgeFeatures?.includes('incremental')) {\n return 'polling'\n }\n\n return 'unsupported'\n}\n","import type { DeploymentMode } from './constants.js'\n\nexport function getDeploymentMode(): DeploymentMode {\n return (process.env.DEPLOYMENT_MODE as DeploymentMode) ?? 'enterprise'\n}\n\nexport function isSaasMode(): boolean {\n return getDeploymentMode() === 'saas'\n}\n"],"mappings":"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","names":[]}