@mauroandre/weave-sdk 0.0.1
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/chunk-PWTED7ZO.js +767 -0
- package/dist/chunk-PWTED7ZO.js.map +1 -0
- package/dist/cli.d.ts +50 -0
- package/dist/cli.js +169 -0
- package/dist/cli.js.map +1 -0
- package/dist/index.d.ts +148 -0
- package/dist/index.js +189 -0
- package/dist/index.js.map +1 -0
- package/dist/scope-DrcCzdf-.d.ts +100 -0
- package/package.json +47 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../core/src/schema/column.ts","../../core/src/schema/owned.ts","../../core/src/schema/reference.ts","../../core/src/types/pg-type.ts","../../core/src/types/catalog.ts","../../core/src/types/registry.ts","../../core/src/schema/scalars.ts","../../core/src/schema/entity.ts","../../core/src/ir/to-ir.ts","../src/errors.ts","../src/push.ts","../src/config.ts","../src/scope.ts","../src/gen.ts"],"sourcesContent":["/**\n * Column builder (Phase 1a; `hasDefault` added at the type level in Phase 2c).\n *\n * A `Column` wraps a {@link PgType} from the catalog and layers column-level\n * modifiers on top. It is **immutable**: every modifier returns a *new* column,\n * so type narrowing is correct and config never leaks between uses.\n *\n * Two facts are tracked at the type level:\n * - **nullability** (`TNotNull`): changes the *read* type (`T` vs `T | null`).\n * - **hasDefault** (`THasDefault`): changes the *insert* type — a notNull\n * column with a default becomes optional on insert (the DB fills it).\n */\n\nimport type { PgType, Infer } from \"../types/pg-type.js\";\n\n/** Runtime description of a column, consumed by the DDL layer. */\nexport interface ColumnConfig {\n /** Stable field id (UUID) — survives rename. Normally born from `weave gen`; absent for hand-written, id-less fields. */\n readonly id?: string;\n /** The underlying catalog type. For arrays, the *element* type. */\n readonly pgType: PgType;\n /** Whether this is `type[]` rather than a scalar `type`. */\n readonly isArray: boolean;\n /** `NOT NULL` when true. */\n readonly notNull: boolean;\n /** Whether a default was declared. */\n readonly hasDefault: boolean;\n /** The declared default (literal value, or `[]` for arrays). Present iff `hasDefault`. */\n readonly default?: unknown;\n /** Single-column `UNIQUE`. */\n readonly unique: boolean;\n /** Single-column btree index. */\n readonly index: boolean;\n}\n\n/**\n * A column over data type `TData`.\n *\n * @typeParam TData - the TS value type (e.g. `string`, `string[]`).\n * @typeParam TNotNull - `true` once `.notNull()` (or an array default) applies.\n * @typeParam THasDefault - `true` once a default exists (`.default()` or array).\n */\nexport class Column<\n TData,\n TNotNull extends boolean = false,\n THasDefault extends boolean = false,\n> {\n /** Phantom carrier so the compiler can recover the type params. No runtime field. */\n declare readonly _types: { data: TData; notNull: TNotNull; hasDefault: THasDefault };\n\n constructor(readonly config: ColumnConfig) {}\n\n /** Mark the column `NOT NULL` — narrows the read type from `T | null` to `T`. */\n notNull(): Column<TData, true, THasDefault> {\n return new Column({ ...this.config, notNull: true });\n }\n\n /** Mark the column nullable — widens the read type back to `T | null`. */\n nullable(): Column<TData, false, THasDefault> {\n return new Column({ ...this.config, notNull: false });\n }\n\n /** Declare a default value — makes the column optional on insert. */\n default(value: TData): Column<TData, TNotNull, true> {\n return new Column({ ...this.config, hasDefault: true, default: value });\n }\n\n /** Add a single-column `UNIQUE`. */\n unique(): Column<TData, TNotNull, THasDefault> {\n return new Column({ ...this.config, unique: true });\n }\n\n /** Add a single-column index. */\n index(): Column<TData, TNotNull, THasDefault> {\n return new Column({ ...this.config, index: true });\n }\n\n /** Pin a stable field id (survives rename). Normally emitted by `weave gen`. */\n $id(id: string): Column<TData, TNotNull, THasDefault> {\n return new Column({ ...this.config, id });\n }\n}\n\n/** A column of any shape — for constraints where the data type is irrelevant. */\nexport type AnyColumn = Column<unknown, boolean, boolean>;\n\n/** The TS type a column reads as, accounting for nullability. */\nexport type InferColumn<C> =\n C extends Column<infer TData, infer TNotNull, boolean>\n ? TNotNull extends true\n ? TData\n : TData | null\n : never;\n\n/** Build a fresh scalar column from a catalog type (nullable, no default). */\nexport function scalarColumn<T extends PgType>(pgType: T): Column<Infer<T>, false, false> {\n return new Column<Infer<T>, false, false>({\n pgType,\n isArray: false,\n notNull: false,\n hasDefault: false,\n unique: false,\n index: false,\n });\n}\n","/**\n * `owned` relationship — composition (Phase 2).\n *\n * An owned sub-shape is stored in a **dedicated child table**, prefixed by the\n * ownership path, with an FK to the immediate parent and `ON DELETE CASCADE`.\n * It can nest recursively (owned within owned). Cardinality:\n *\n * - `owned({...})` → 1:1, one child row.\n * - `owned(array({...}))` → 1:N, many child rows.\n *\n * Owned sub-entities get their own `id`/`createdAt`/`updatedAt`, like any table.\n */\n\nimport { Column } from \"./column.js\";\nimport type { AnyReference } from \"./reference.js\";\n\nexport type OwnedCardinality = \"one\" | \"many\";\n\n/** A sub-shape: columns, further owned relationships, and/or references. */\nexport type OwnedShape = Record<\n string,\n Column<unknown, boolean, boolean> | AnyOwned | AnyReference\n>;\n\n/** Options for an owned relationship. */\nexport interface OwnedOptions {\n /** Override the generated child-table name (escape valve for deep nesting). */\n table?: string;\n}\n\n/** An owned relationship node in a shape. */\nexport class Owned<TShape extends OwnedShape, TCard extends OwnedCardinality> {\n readonly kind = \"owned\" as const;\n constructor(\n readonly shape: TShape,\n readonly cardinality: TCard,\n readonly options: OwnedOptions,\n /** Stable field id (UUID) — survives rename. Normally emitted by `weave gen`. */\n readonly id?: string,\n ) {}\n\n /** Pin a stable field id (survives rename). Normally emitted by `weave gen`. */\n $id(id: string): Owned<TShape, TCard> {\n return new Owned(this.shape, this.cardinality, this.options, id);\n }\n}\n\n/** An owned relationship of any shape/cardinality. */\nexport type AnyOwned = Owned<OwnedShape, OwnedCardinality>;\n\n/** Marker produced by `array({...})` to signal a 1:N owned set. */\nexport class OwnedArray<TShape extends OwnedShape> {\n readonly kind = \"owned_array\" as const;\n constructor(readonly shape: TShape) {}\n}\n\n/** Declare an owned 1:1 relationship. */\nexport function owned<TShape extends OwnedShape>(\n shape: TShape,\n options?: OwnedOptions,\n): Owned<TShape, \"one\">;\n/** Declare an owned 1:N relationship (from `array({...})`). */\nexport function owned<TShape extends OwnedShape>(\n set: OwnedArray<TShape>,\n options?: OwnedOptions,\n): Owned<TShape, \"many\">;\nexport function owned(\n arg: OwnedShape | OwnedArray<OwnedShape>,\n options: OwnedOptions = {},\n): Owned<OwnedShape, OwnedCardinality> {\n if (arg instanceof OwnedArray) {\n return new Owned(arg.shape, \"many\", options);\n }\n return new Owned(arg, \"one\", options);\n}\n","/**\n * `reference` relationship — association (Phases 3 & 4).\n *\n * The target is an **independent** entity (its own table), possibly shared by\n * many. This side only **points and reads**: it never writes the target table.\n *\n * - `reference(city)` → N:1. FK column `city_id` (no cascade).\n * Reads `cityId` always, `city` on expand.\n * - `reference(array(city))` → N:N. A join table (`user_cities`), composite\n * PK, both FKs cascade the *link*. Reads nothing\n * by default; `cities: City[]` on expand. Writes\n * via `citiesIds: string[]` (replaces the set).\n */\n\nimport type { Entity, ShapeRecord } from \"./entity.js\";\n\nexport type ReferenceCardinality = \"one\" | \"many\";\n\nexport class Reference<\n TTarget extends Entity<string, ShapeRecord> = Entity<string, ShapeRecord>,\n TCard extends ReferenceCardinality = \"one\",\n TNotNull extends boolean = false,\n> {\n readonly kind = \"reference\" as const;\n /** Phantom carrier so the compiler can recover target/cardinality/nullability. */\n declare readonly _phantom: { target: TTarget; cardinality: TCard; notNull: TNotNull };\n\n constructor(\n readonly target: TTarget,\n readonly cardinality: TCard,\n readonly isNotNull: boolean,\n /** Stable field id (UUID) — survives rename. Normally emitted by `weave gen`. */\n readonly id?: string,\n ) {}\n\n /** Make the FK `NOT NULL` (only meaningful for N:1). */\n notNull(): Reference<TTarget, TCard, true> {\n return new Reference<TTarget, TCard, true>(this.target, this.cardinality, true, this.id);\n }\n\n /** Pin a stable field id (survives rename). Normally emitted by `weave gen`. */\n $id(id: string): Reference<TTarget, TCard, TNotNull> {\n return new Reference<TTarget, TCard, TNotNull>(this.target, this.cardinality, this.isNotNull, id);\n }\n}\n\n/** A reference of any target/cardinality/nullability. */\nexport type AnyReference = Reference<Entity<string, ShapeRecord>, ReferenceCardinality, boolean>;\n\n/** Marker produced by `array(entity)` to signal an N:N reference. */\nexport class ReferenceArray<TTarget extends Entity<string, ShapeRecord>> {\n readonly kind = \"reference_array\" as const;\n constructor(readonly target: TTarget) {}\n}\n\n/** Declare an N:1 reference to an independent entity (nullable by default). */\nexport function reference<T extends Entity<string, ShapeRecord>>(\n target: T,\n): Reference<T, \"one\", false>;\n/** Declare an N:N reference (from `array(entity)`). */\nexport function reference<T extends Entity<string, ShapeRecord>>(\n set: ReferenceArray<T>,\n): Reference<T, \"many\", false>;\nexport function reference(\n arg: Entity<string, ShapeRecord> | ReferenceArray<Entity<string, ShapeRecord>>,\n): Reference<Entity<string, ShapeRecord>, ReferenceCardinality, false> {\n if (arg instanceof ReferenceArray) {\n return new Reference(arg.target, \"many\", false);\n }\n return new Reference(arg, \"one\", false);\n}\n","/**\n * The Postgres type catalog (Phase 0).\n *\n * Each Postgres type is described once, as a plain TS object that serves two\n * masters at the same time:\n *\n * - runtime → `oid` + `sqlType`: emit DDL and match columns against the live\n * database during a diff (Postgres speaks in OIDs, not names).\n * - compile → `tsType`: a *phantom* field carrying the corresponding TS type\n * so the shape can infer `number`/`string`/`Date`/... with zero\n * runtime cost. It is `undefined` at runtime.\n *\n * `tsLabel` is the runtime-visible string twin of `tsType` (e.g. \"number\"),\n * reserved for future codegen (edge validation / Zod) and debugging.\n */\n\n/** Runtime-visible label of the TS type a column hydrates to. */\nexport type TsLabel =\n | \"string\"\n | \"number\"\n | \"bigint\"\n | \"boolean\"\n | \"Date\"\n | \"Uint8Array\"\n | \"unknown\";\n\n/**\n * A single entry in the Postgres type catalog.\n *\n * @typeParam TName - the catalog key and discriminant (e.g. \"int4\").\n * @typeParam TTs - the TS type a value of this column hydrates to.\n */\nexport interface PgType<TName extends string = string, TTs = unknown> {\n /** Catalog key + discriminant. Matches the short Postgres type name. */\n readonly name: TName;\n /** Canonical SQL text emitted in DDL (e.g. \"integer\", \"timestamp with time zone\"). */\n readonly sqlType: string;\n /** Stable Postgres OID (from `pg_type`), the robust key for diffing. */\n readonly oid: number;\n /** Runtime-visible twin of `tsType`, for codegen/debug. */\n readonly tsLabel: TsLabel;\n /**\n * Phantom carrier of the TS type. Always `undefined` at runtime — read it\n * only at the type level via {@link Infer}.\n */\n readonly tsType: TTs;\n}\n\n/** Definition object accepted by {@link defineType} (everything but the phantom). */\nexport interface PgTypeDef<TName extends string> {\n readonly name: TName;\n readonly sqlType: string;\n readonly oid: number;\n readonly tsLabel: TsLabel;\n}\n\n/**\n * Build a {@link PgType}, binding the runtime fields to the phantom `TTs` type.\n *\n * `TTs` is supplied explicitly (it has no runtime representation), while `TName`\n * is inferred from the literal `name`:\n *\n * ```ts\n * const int4 = defineType<number>({ name: \"int4\", sqlType: \"integer\", oid: 23, tsLabel: \"number\" });\n * ```\n */\nexport function defineType<TTs>() {\n return <TName extends string>(def: PgTypeDef<TName>): PgType<TName, TTs> => ({\n ...def,\n // Phantom: exists only so the compiler can recover `TTs`. Never read at runtime.\n tsType: undefined as TTs,\n });\n}\n\n/** Extract the TS type a {@link PgType} hydrates to. */\nexport type Infer<T extends PgType> = T[\"tsType\"];\n","/**\n * The core Postgres type catalog (~20 scalars) for v1.\n *\n * OIDs are the stable values hardcoded in Postgres' `pg_type` (mirrored by\n * `pg-types`' `builtins`). `sqlType` is the canonical SQL spelling emitted in\n * DDL. The TS mapping follows the decisions in the PRD:\n *\n * - int8 → bigint (number can't hold it losslessly)\n * - numeric → number (ergonomics over precision; column stays exact)\n * - date/timestamp(tz) → Date\n * - time/interval → string (no native JS type; lossless as text)\n * - json/jsonb → unknown (schemaless by nature)\n * - bytea → Uint8Array\n *\n * Exotic types (ranges, network, geometric, tsvector) are intentionally out of\n * scope for v1.\n */\n\nimport { defineType } from \"./pg-type.js\";\n\n// ── Numeric ────────────────────────────────────────────────────────────────\nexport const int2 = defineType<number>()({ name: \"int2\", sqlType: \"smallint\", oid: 21, tsLabel: \"number\" });\nexport const int4 = defineType<number>()({ name: \"int4\", sqlType: \"integer\", oid: 23, tsLabel: \"number\" });\nexport const int8 = defineType<bigint>()({ name: \"int8\", sqlType: \"bigint\", oid: 20, tsLabel: \"bigint\" });\nexport const numeric = defineType<number>()({ name: \"numeric\", sqlType: \"numeric\", oid: 1700, tsLabel: \"number\" });\nexport const float4 = defineType<number>()({ name: \"float4\", sqlType: \"real\", oid: 700, tsLabel: \"number\" });\nexport const float8 = defineType<number>()({ name: \"float8\", sqlType: \"double precision\", oid: 701, tsLabel: \"number\" });\n\n// ── Text ─────────────────────────────────────────────────────────────────────\nexport const text = defineType<string>()({ name: \"text\", sqlType: \"text\", oid: 25, tsLabel: \"string\" });\nexport const varchar = defineType<string>()({ name: \"varchar\", sqlType: \"varchar\", oid: 1043, tsLabel: \"string\" });\nexport const bpchar = defineType<string>()({ name: \"bpchar\", sqlType: \"char\", oid: 1042, tsLabel: \"string\" });\n\n// ── Date / time ──────────────────────────────────────────────────────────────\nexport const timestamptz = defineType<Date>()({ name: \"timestamptz\", sqlType: \"timestamp with time zone\", oid: 1184, tsLabel: \"Date\" });\nexport const timestamp = defineType<Date>()({ name: \"timestamp\", sqlType: \"timestamp\", oid: 1114, tsLabel: \"Date\" });\nexport const date = defineType<Date>()({ name: \"date\", sqlType: \"date\", oid: 1082, tsLabel: \"Date\" });\nexport const time = defineType<string>()({ name: \"time\", sqlType: \"time\", oid: 1083, tsLabel: \"string\" });\nexport const interval = defineType<string>()({ name: \"interval\", sqlType: \"interval\", oid: 1186, tsLabel: \"string\" });\n\n// ── Boolean ──────────────────────────────────────────────────────────────────\nexport const bool = defineType<boolean>()({ name: \"bool\", sqlType: \"boolean\", oid: 16, tsLabel: \"boolean\" });\n\n// ── Identity ─────────────────────────────────────────────────────────────────\nexport const uuid = defineType<string>()({ name: \"uuid\", sqlType: \"uuid\", oid: 2950, tsLabel: \"string\" });\n\n// ── Document ─────────────────────────────────────────────────────────────────\nexport const json = defineType<unknown>()({ name: \"json\", sqlType: \"json\", oid: 114, tsLabel: \"unknown\" });\nexport const jsonb = defineType<unknown>()({ name: \"jsonb\", sqlType: \"jsonb\", oid: 3802, tsLabel: \"unknown\" });\n\n// ── Binary ───────────────────────────────────────────────────────────────────\nexport const bytea = defineType<Uint8Array>()({ name: \"bytea\", sqlType: \"bytea\", oid: 17, tsLabel: \"Uint8Array\" });\n","/**\n * Lookup structures over the catalog.\n *\n * `byName` and `byOid` are the runtime indexes used by the DDL/diff layer to\n * resolve a type from a shape declaration (by name) or from the live database\n * (by OID — what `pg_attribute` / wire metadata reports).\n */\n\nimport type { PgType } from \"./pg-type.js\";\nimport * as types from \"./catalog.js\";\n\n/** Every catalog entry, keyed by its short Postgres name. */\nexport const catalog = {\n int2: types.int2,\n int4: types.int4,\n int8: types.int8,\n numeric: types.numeric,\n float4: types.float4,\n float8: types.float8,\n text: types.text,\n varchar: types.varchar,\n bpchar: types.bpchar,\n timestamptz: types.timestamptz,\n timestamp: types.timestamp,\n date: types.date,\n time: types.time,\n interval: types.interval,\n bool: types.bool,\n uuid: types.uuid,\n json: types.json,\n jsonb: types.jsonb,\n bytea: types.bytea,\n} as const;\n\nexport type CatalogName = keyof typeof catalog;\n\n/** All catalog entries as a flat list. */\nexport const allTypes: readonly PgType[] = Object.values(catalog);\n\n/** Resolve a type by its short Postgres name (e.g. \"int4\"). */\nexport const byName: ReadonlyMap<string, PgType> = new Map(\n allTypes.map((t) => [t.name, t]),\n);\n\n/** Resolve a type by its Postgres OID (e.g. 23 → int4). */\nexport const byOid: ReadonlyMap<number, PgType> = new Map(\n allTypes.map((t) => [t.oid, t]),\n);\n","/**\n * Public column constructors — the shape-declaration surface.\n *\n * Each constructor returns a fresh, nullable {@link Column} over the matching\n * catalog type. Chain modifiers to refine it: `text().notNull().unique()`.\n */\n\nimport { catalog } from \"../types/registry.js\";\nimport { Column, scalarColumn, type AnyColumn } from \"./column.js\";\nimport { OwnedArray, type OwnedShape } from \"./owned.js\";\nimport { ReferenceArray } from \"./reference.js\";\nimport type { Entity, ShapeRecord } from \"./entity.js\";\n\n// ── Numeric ──────────────────────────────────────────────────────────────────\nexport const int2 = () => scalarColumn(catalog.int2);\nexport const int4 = () => scalarColumn(catalog.int4);\nexport const int8 = () => scalarColumn(catalog.int8);\nexport const numeric = () => scalarColumn(catalog.numeric);\nexport const float4 = () => scalarColumn(catalog.float4);\nexport const float8 = () => scalarColumn(catalog.float8);\n\n// ── Text ─────────────────────────────────────────────────────────────────────\nexport const text = () => scalarColumn(catalog.text);\nexport const varchar = () => scalarColumn(catalog.varchar);\nexport const bpchar = () => scalarColumn(catalog.bpchar);\n\n// ── Date / time ──────────────────────────────────────────────────────────────\nexport const timestamptz = () => scalarColumn(catalog.timestamptz);\nexport const timestamp = () => scalarColumn(catalog.timestamp);\nexport const date = () => scalarColumn(catalog.date);\nexport const time = () => scalarColumn(catalog.time);\nexport const interval = () => scalarColumn(catalog.interval);\n\n// ── Boolean ──────────────────────────────────────────────────────────────────\nexport const bool = () => scalarColumn(catalog.bool);\n\n// ── Identity ─────────────────────────────────────────────────────────────────\nexport const uuid = () => scalarColumn(catalog.uuid);\n\n// ── Document ─────────────────────────────────────────────────────────────────\nexport const json = () => scalarColumn(catalog.json);\nexport const jsonb = () => scalarColumn(catalog.jsonb);\n\n// ── Binary ───────────────────────────────────────────────────────────────────\nexport const bytea = () => scalarColumn(catalog.bytea);\n\n/**\n * `array(...)` is overloaded by what it wraps:\n *\n * - `array(text())` → a **scalar array column** (`text[]`).\n * - `array(cityEntity)`→ an **N:N reference marker** for `reference(array(city))`.\n * - `array({ ... })` → an **owned 1:N marker** for `owned(array({...}))`.\n *\n * Scalar arrays default to **`NOT NULL DEFAULT '{}'`** (you always get `[]`,\n * never `null`); opt out with `array(text()).nullable()`.\n */\nexport function array<TData>(\n inner: Column<TData, boolean, boolean>,\n): Column<TData[], true, true>;\nexport function array<T extends Entity<string, ShapeRecord>>(target: T): ReferenceArray<T>;\nexport function array<TShape extends OwnedShape>(shape: TShape): OwnedArray<TShape>;\nexport function array(\n arg: Column<unknown, boolean, boolean> | Entity<string, ShapeRecord> | OwnedShape,\n): Column<unknown[], true, true> | ReferenceArray<Entity<string, ShapeRecord>> | OwnedArray<OwnedShape> {\n if (arg instanceof Column) {\n return new Column<unknown[], true, true>({\n pgType: arg.config.pgType,\n isArray: true,\n notNull: true,\n hasDefault: true,\n default: [],\n unique: false,\n index: false,\n });\n }\n // An Entity has a string `name` and an object `columns`; a shape does not.\n const candidate = arg as { name?: unknown; columns?: unknown };\n if (typeof candidate.name === \"string\" && typeof candidate.columns === \"object\") {\n return new ReferenceArray(arg as Entity<string, ShapeRecord>);\n }\n return new OwnedArray(arg as OwnedShape);\n}\n\nexport type { AnyColumn };\n","/**\n * Entity declaration + inference.\n *\n * `defineEntity` captures the user's shape and, conceptually, owns three managed\n * system columns every (sub-)entity gets: `id` (uuid PK), `createdAt`,\n * `updatedAt`. Inference produces three views of a shape:\n *\n * - {@link InferRead} — the read object, parameterized by an `expand` map.\n * `owned` nests automatically; a `reference` surfaces\n * as `<field>Id` always, plus `<field>` when expanded.\n * - {@link InferEntity} — `InferRead` with no expand (the default read shape).\n * - {@link InferInsert} — the write object: notNull-without-default columns are\n * required, references are set via `<field>Id`.\n */\n\nimport type { Column, InferColumn } from \"./column.js\";\nimport type { AnyOwned, OwnedShape, Owned, OwnedCardinality } from \"./owned.js\";\nimport type { AnyReference } from \"./reference.js\";\n\n/** A record of named fields — columns, owned relationships, and/or references. */\nexport type ShapeRecord = Record<\n string,\n Column<unknown, boolean, boolean> | AnyOwned | AnyReference\n>;\n\n/** The managed system columns every (sub-)entity carries. */\nexport interface SystemColumns {\n id: string;\n createdAt: Date;\n updatedAt: Date;\n}\n\n/** Flatten an intersection into a single object literal for readable hovers. */\ntype Prettify<T> = { [K in keyof T]: T[K] } & {};\n\n/** A declared entity: a table name plus its shape. */\nexport interface Entity<TName extends string, TShape extends ShapeRecord> {\n readonly name: TName;\n readonly columns: TShape;\n}\n\n// ── Field discriminators (by phantom / kind tag) ─────────────────────────────\n\ntype IsColumn<V> = V extends { _types: unknown } ? true : false;\ntype IsOwned<V> = V extends { kind: \"owned\" } ? true : false;\ntype IsReference<V> = V extends { kind: \"reference\" } ? true : false;\ntype IsRefOne<V> = IsReference<V> extends true ? (RefCard<V> extends \"one\" ? true : false) : false;\ntype IsRefMany<V> = IsReference<V> extends true ? (RefCard<V> extends \"many\" ? true : false) : false;\n\ntype RefTargetShape<V> =\n V extends { _phantom: { target: Entity<string, infer TS> } } ? TS : never;\ntype RefNotNull<V> = V extends { _phantom: { notNull: infer NN } } ? NN : false;\ntype RefCard<V> = V extends { _phantom: { cardinality: infer C } } ? C : \"one\";\n\n/** Recursion-depth budget for cyclic schemas (caps nested expand types). */\ntype Budget = [unknown, unknown, unknown, unknown, unknown, unknown];\ntype Drop<D extends unknown[]> = D extends [unknown, ...infer R] ? R : [];\n\n// ── Read inference (expand-parameterized) ────────────────────────────────────\n\n/** The sub-expand map for key `K` (or `{}` when absent / `true`). */\ntype ExpandFor<X, K extends PropertyKey> = K extends keyof X\n ? X[K] extends true\n ? {}\n : X[K]\n : {};\n\ntype ReadBody<TShape, X> = {\n [K in keyof TShape as IsColumn<TShape[K]> extends true ? K : never]: InferColumn<TShape[K]>;\n} & {\n [K in keyof TShape as IsOwned<TShape[K]> extends true ? K : never]: TShape[K] extends Owned<\n infer S,\n infer C\n >\n ? C extends \"many\"\n ? Prettify<ReadShape<S, ExpandFor<X, K>>>[]\n : Prettify<ReadShape<S, ExpandFor<X, K>>>\n : never;\n} & {\n // N:1 FK id — always present.\n [K in keyof TShape as IsRefOne<TShape[K]> extends true\n ? `${K & string}Id`\n : never]: RefNotNull<TShape[K]> extends true ? string : string | null;\n} & {\n // N:1 expanded target — only for keys present in the expand map.\n [K in keyof TShape as IsRefOne<TShape[K]> extends true\n ? K extends keyof X\n ? K\n : never\n : never]: RefNotNull<TShape[K]> extends true\n ? Prettify<ReadShape<RefTargetShape<TShape[K]>, ExpandFor<X, K>>>\n : Prettify<ReadShape<RefTargetShape<TShape[K]>, ExpandFor<X, K>>> | null;\n} & {\n // N:N expanded targets — array, only when expanded (nothing by default).\n [K in keyof TShape as IsRefMany<TShape[K]> extends true\n ? K extends keyof X\n ? K\n : never\n : never]: Prettify<ReadShape<RefTargetShape<TShape[K]>, ExpandFor<X, K>>>[];\n};\n\n// Raw intersection (no Prettify here, so the recursive alias stays lazy).\ntype ReadShape<TShape, X> = Pick<SystemColumns, \"id\"> &\n ReadBody<TShape, X> &\n Pick<SystemColumns, \"createdAt\" | \"updatedAt\">;\n\n/** The read object for an entity, given an `expand` map `X`. */\nexport type InferRead<E, X> = E extends Entity<string, infer TShape>\n ? Prettify<ReadShape<TShape, X>>\n : never;\n\n/** The default read object (no expand). */\nexport type InferEntity<E> = InferRead<E, {}>;\n\n// ── Expand map ───────────────────────────────────────────────────────────────\n\ntype ExpandShape<TShape, D extends unknown[] = Budget> = D extends []\n ? {} // depth budget exhausted — stop recursing (cycle guard)\n : {\n [K in keyof TShape as IsReference<TShape[K]> extends true\n ? K\n : IsOwned<TShape[K]> extends true\n ? K\n : never]?: IsReference<TShape[K]> extends true\n ? true | ExpandShape<RefTargetShape<TShape[K]>, Drop<D>>\n : TShape[K] extends Owned<infer S, OwnedCardinality>\n ? ExpandShape<S, Drop<D>>\n : never;\n };\n\n/** The shape of the `expand` option for an entity. */\nexport type ExpandInput<E> = E extends Entity<string, infer TShape>\n ? ExpandShape<TShape>\n : never;\n\n// ── Insert inference ─────────────────────────────────────────────────────────\n\ntype InsertField<V> =\n IsColumn<V> extends true\n ? V extends Column<infer TData, infer NN, boolean>\n ? NN extends true\n ? TData\n : TData | null\n : never\n : IsOwned<V> extends true\n ? V extends Owned<infer S, infer C>\n ? C extends \"many\"\n ? InsertOwned<S>[]\n : InsertOwned<S>\n : never\n : never;\n\n/** A column is required on insert only if it is `notNull` AND has no default. */\ntype RequiredColumn<V> = V extends { _types: { notNull: true; hasDefault: false } }\n ? true\n : false;\n\ntype InsertBody<TShape> = Prettify<\n {\n [K in keyof TShape as IsColumn<TShape[K]> extends true\n ? RequiredColumn<TShape[K]> extends true\n ? K\n : never\n : never]: InsertField<TShape[K]>;\n } & {\n [K in keyof TShape as IsColumn<TShape[K]> extends true\n ? RequiredColumn<TShape[K]> extends true\n ? never\n : K\n : never]?: InsertField<TShape[K]>;\n } & {\n [K in keyof TShape as IsOwned<TShape[K]> extends true ? K : never]?: InsertField<TShape[K]>;\n } & {\n // notNull N:1 reference → required `<field>Id`.\n [K in keyof TShape as IsRefOne<TShape[K]> extends true\n ? RefNotNull<TShape[K]> extends true\n ? `${K & string}Id`\n : never\n : never]: string;\n } & {\n // nullable N:1 reference → optional `<field>Id`.\n [K in keyof TShape as IsRefOne<TShape[K]> extends true\n ? RefNotNull<TShape[K]> extends true\n ? never\n : `${K & string}Id`\n : never]?: string;\n } & {\n // N:N reference → optional `<field>Ids` (the link set; absent = empty).\n [K in keyof TShape as IsRefMany<TShape[K]> extends true\n ? `${K & string}Ids`\n : never]?: string[];\n }\n>;\n\ntype InsertOwned<S extends OwnedShape> = Prettify<{ id?: string } & InsertBody<S>>;\n\n/** The object accepted by `save`: optional id (upsert), body, no managed timestamps. */\nexport type InferInsert<E> = E extends Entity<string, infer TShape>\n ? Prettify<{ id?: string } & InsertBody<TShape>>\n : never;\n\n// ── Projection (`select`, Phase 6) ───────────────────────────────────────────\n\ntype SelectShape<TShape, D extends unknown[] = Budget> = {\n id?: true;\n createdAt?: true;\n updatedAt?: true;\n} & {\n [K in keyof TShape as IsColumn<TShape[K]> extends true ? K : never]?: true;\n} & {\n [K in keyof TShape as IsRefOne<TShape[K]> extends true ? `${K & string}Id` : never]?: true;\n} & (D extends []\n ? {}\n : {\n [K in keyof TShape as IsOwned<TShape[K]> extends true ? K : never]?:\n | true\n | (TShape[K] extends Owned<infer S, OwnedCardinality> ? SelectShape<S, Drop<D>> : never);\n } & {\n [K in keyof TShape as IsRefOne<TShape[K]> extends true\n ? K\n : IsRefMany<TShape[K]> extends true\n ? K\n : never]?: true | SelectShape<RefTargetShape<TShape[K]>, Drop<D>>;\n });\n\n/** The shape of the `select` option for an entity. */\nexport type SelectInput<E> = E extends Entity<string, infer TShape> ? SelectShape<TShape> : never;\n\n/** Full read of a sub-shape (all fields, references as ids) — used by `true`. */\ntype FullRead<TShape> = Prettify<ReadShape<TShape, {}>>;\n\ntype SelectSub<SubShape, Sel> = Sel extends true ? FullRead<SubShape> : SelectResultShape<SubShape, Sel>;\n\ntype SelectFieldType<TShape, K, Sel> = K extends \"id\"\n ? string\n : K extends \"createdAt\" | \"updatedAt\"\n ? Date\n : K extends keyof TShape\n ? IsColumn<TShape[K]> extends true\n ? InferColumn<TShape[K]>\n : TShape[K] extends Owned<infer S, infer C>\n ? C extends \"many\"\n ? SelectSub<S, Sel>[]\n : SelectSub<S, Sel>\n : IsRefOne<TShape[K]> extends true\n ? RefNotNull<TShape[K]> extends true\n ? SelectSub<RefTargetShape<TShape[K]>, Sel>\n : SelectSub<RefTargetShape<TShape[K]>, Sel> | null\n : IsRefMany<TShape[K]> extends true\n ? SelectSub<RefTargetShape<TShape[K]>, Sel>[]\n : never\n : K extends `${infer F}Id`\n ? F extends keyof TShape\n ? IsRefOne<TShape[F]> extends true\n ? RefNotNull<TShape[F]> extends true\n ? string\n : string | null\n : never\n : never\n : never;\n\ntype SelectResultShape<TShape, S> = Prettify<\n { id: string } & { [K in keyof S]: SelectFieldType<TShape, K, S[K]> }\n>;\n\n/** The pruned read object for an entity, given a `select` map `S`. */\nexport type InferSelect<E, S> = E extends Entity<string, infer TShape>\n ? SelectResultShape<TShape, S>\n : never;\n\n/** Declare an entity (a first-class table). */\nexport function defineEntity<TName extends string, TShape extends ShapeRecord>(\n name: TName,\n columns: TShape,\n): Entity<TName, TShape> {\n return { name, columns };\n}\n","import { Column } from \"../schema/column.js\";\nimport { Owned, type OwnedShape } from \"../schema/owned.js\";\nimport { Reference } from \"../schema/reference.js\";\nimport type { Entity, ShapeRecord } from \"../schema/entity.js\";\nimport type { ColumnIR, EntityIR, FieldIR, OwnedIR, ReferenceIR } from \"./types.js\";\n\n/**\n * Serializa um `Entity` (saída do `defineEntity`) de volta pro IR JSON — o\n * caminho de IDA, inverso do `fromIR`. É o elo que o SDK usa pra transformar o\n * schema-as-code do dev no IR que o `push` manda pro servidor.\n *\n * Escopo: formas CONCRETAS (column/owned/reference). `mirror` é resolvido ANTES\n * do `fromIR` no pipeline real, e o builder ainda não carrega marca de mirror,\n * então `toIR` não emite `mirror` (fica pra quando o builder ganhar `mirror()`).\n * Emite `id` quando o campo o carrega (via `.$id(...)`, normalmente do `weave\n * gen`); ausente em campos id-less escritos à mão (o servidor cunha no apply).\n *\n * Saída CANÔNICA/mínima: optionals falsos são omitidos (`array:false`,\n * `notNull:false`, …), pra `toIR(fromIR(ir))` reproduzir o IR mínimo de origem.\n */\nexport function toIR(entity: Entity<string, ShapeRecord>): EntityIR {\n return { irVersion: 1, name: entity.name, fields: shapeToIR(entity.columns) };\n}\n\nfunction shapeToIR(shape: ShapeRecord | OwnedShape): Record<string, FieldIR> {\n const out: Record<string, FieldIR> = {};\n for (const [key, node] of Object.entries(shape)) out[key] = nodeToIR(node);\n return out;\n}\n\nfunction nodeToIR(node: ShapeRecord[string]): FieldIR {\n if (node instanceof Column) {\n const c = node.config;\n const ir: ColumnIR = { kind: \"column\", type: c.pgType.name };\n if (c.id) ir.id = c.id;\n if (c.isArray) ir.array = true;\n if (c.notNull) ir.notNull = true;\n if (c.hasDefault) ir.default = c.default;\n if (c.unique) ir.unique = true;\n if (c.index) ir.index = true;\n return ir;\n }\n if (node instanceof Reference) {\n const ir: ReferenceIR = {\n kind: \"reference\",\n target: node.target.name,\n cardinality: node.cardinality,\n };\n if (node.id) ir.id = node.id;\n if (node.isNotNull) ir.notNull = true;\n return ir;\n }\n if (node instanceof Owned) {\n const ir: OwnedIR = {\n kind: \"owned\",\n array: node.cardinality === \"many\",\n shape: shapeToIR(node.shape),\n };\n if (node.id) ir.id = node.id;\n if (node.options.table !== undefined) ir.table = node.options.table;\n return ir;\n }\n throw new Error(\"toIR — nó desconhecido no shape (esperado Column/Owned/Reference).\");\n}\n","// Erros de domínio do SDK — o dev pega um erro em vocabulário de objeto, NUNCA um\n// stack de SQL. Mapeados a partir do status HTTP que a API devolve.\n\nexport class WeaveError extends Error {\n constructor(\n message: string,\n readonly status: number,\n ) {\n super(message);\n this.name = \"WeaveError\";\n }\n}\n\n/** 401 — a API key falta ou é inválida. */\nexport class WeaveAuthError extends WeaveError {\n constructor(message: string) {\n super(message, 401);\n this.name = \"WeaveAuthError\";\n }\n}\n\n/** 403 — o scope nega o verbo/linha/campo. */\nexport class WeaveScopeError extends WeaveError {\n constructor(message: string) {\n super(message, 403);\n this.name = \"WeaveScopeError\";\n }\n}\n\n/** 404 — objeto inexistente (ou fora do alcance do scope). */\nexport class WeaveNotFoundError extends WeaveError {\n constructor(message: string) {\n super(message, 404);\n this.name = \"WeaveNotFoundError\";\n }\n}\n\n/** 400 — payload inválido (validação de borda). */\nexport class WeaveValidationError extends WeaveError {\n constructor(message: string) {\n super(message, 400);\n this.name = \"WeaveValidationError\";\n }\n}\n\n/** Constrói o erro tipado a partir do status HTTP. */\nexport function errorFor(status: number, message: string): WeaveError {\n switch (status) {\n case 401:\n return new WeaveAuthError(message);\n case 403:\n return new WeaveScopeError(message);\n case 404:\n return new WeaveNotFoundError(message);\n case 400:\n return new WeaveValidationError(message);\n default:\n return new WeaveError(message, status);\n }\n}\n","import { toIR } from \"@mauroandre/weave-core\";\nimport type { Entity, ShapeRecord, EntityIR, FieldIR } from \"@mauroandre/weave-core\";\nimport { errorFor } from \"./errors.js\";\nimport type { FetchLike } from \"./client.js\";\n\nexport interface PushOptions {\n /** Base URL do Weave. */\n url: string;\n /** API key (`x-api-key`). */\n key: string;\n /** Transporte. Default: `globalThis.fetch`. Nos testes: `app.hono.fetch`. */\n fetch?: FetchLike;\n /** Caminhos confirmados (drops destrutivos), por nome de entidade. */\n confirm?: Record<string, string[]>;\n /** Valores de backfill (caminho → valor), por nome de entidade. */\n fill?: Record<string, Record<string, unknown>>;\n /**\n * Renames de campo, por entidade: `{ entidade: { nomeAntigo: nomeNovo } }`.\n * Sem isso, renomear no código vira drop+add (com gate); aqui injetamos o id\n * existente no campo novo → o servidor detecta um RENAME (dado preservado).\n */\n renames?: Record<string, Record<string, string>>;\n}\n\n/** Uma mudança no plano de migração (em vocabulário de objeto, nunca SQL). */\nexport interface PlanChange {\n op: string;\n path: string;\n /** `auto` 🟢 · `confirm` 🔴 · `needsValue` 🟡 · `blocked` ⛔ */\n risk: string;\n}\nexport interface MigrationPlan {\n changes: PlanChange[];\n}\n\nexport interface PushResult {\n /** Entidades aplicadas (criadas/migradas). */\n applied: string[];\n /** Entidades que precisam de revisão (com o plano por risco). */\n review: { name: string; plan: MigrationPlan }[];\n}\n\n/** Lê o IR atual de uma entidade do servidor (ou null se não existe). */\nasync function fetchIR(transport: FetchLike, base: string, key: string, name: string): Promise<EntityIR | null> {\n const res = await transport(\n new Request(`${base}/admin/entities/${encodeURIComponent(name)}`, { method: \"GET\", headers: { \"x-api-key\": key } }),\n );\n if (!res.ok) return null; // 404 (nova) ou erro → sem renames a aplicar\n return (await res.json().catch(() => null)) as EntityIR | null;\n}\n\n/** Dependências de uma entidade (alvos de reference + mirror), pra ordenar o apply. */\nfunction depsOf(ir: EntityIR): Set<string> {\n const deps = new Set<string>();\n const walk = (fields: Record<string, FieldIR>): void => {\n for (const node of Object.values(fields)) {\n if (node.kind === \"reference\") deps.add(node.target);\n else if (node.kind === \"owned\") {\n if (node.mirror) deps.add(node.mirror);\n if (node.shape) walk(node.shape);\n }\n }\n };\n walk(ir.fields);\n return deps;\n}\n\n/**\n * Empurra o entities-as-code pro Weave: serializa cada entidade (`toIR`) e aplica via\n * `/admin/entities` (plan/apply seguro). Aplica em **ordem de dependência** (a\n * entidade referida antes da que referencia). Devolve o que foi aplicado e o que\n * precisa de revisão (com o plano por risco) — em vocabulário de objeto, sem SQL.\n *\n * `confirm`/`fill` (por entidade) destravam drops confirmados e backfills.\n */\nexport async function pushEntities(\n entities: Record<string, Entity<string, ShapeRecord>>,\n options: PushOptions,\n): Promise<PushResult> {\n const transport: FetchLike = options.fetch ?? ((req) => globalThis.fetch(req));\n const base = options.url.replace(/\\/$/, \"\");\n\n const irs = Object.values(entities).map((e) => ({ name: e.name, ir: toIR(e) }));\n const byName = new Map(irs.map((x) => [x.name, x] as const));\n\n // Topo-sort: dependências (dentro do entities) aplicadas primeiro.\n const ordered: { name: string; ir: EntityIR }[] = [];\n const seen = new Set<string>();\n const visit = (x: { name: string; ir: EntityIR }): void => {\n if (seen.has(x.name)) return;\n seen.add(x.name);\n for (const dep of depsOf(x.ir)) {\n const d = byName.get(dep);\n if (d) visit(d); // deps externas (já existentes no servidor) são assumidas\n }\n ordered.push(x);\n };\n for (const x of irs) visit(x);\n\n const applied: string[] = [];\n const review: { name: string; plan: MigrationPlan }[] = [];\n\n for (const { name, ir } of ordered) {\n // Rename: injeta o id do campo antigo no campo novo (o servidor vê rename).\n const renameMap = options.renames?.[name];\n if (renameMap && Object.keys(renameMap).length > 0) {\n const existing = await fetchIR(transport, base, options.key, name);\n if (existing) {\n const idByOldName = new Map<string, string>();\n for (const [fname, fnode] of Object.entries(existing.fields)) if (fnode.id) idByOldName.set(fname, fnode.id);\n for (const [oldName, newName] of Object.entries(renameMap)) {\n const id = idByOldName.get(oldName);\n const target = ir.fields[newName];\n if (id && target) ir.fields = { ...ir.fields, [newName]: { ...target, id } };\n }\n }\n }\n\n const body: Record<string, unknown> = { ir };\n if (options.confirm?.[name]) body.confirm = options.confirm[name];\n if (options.fill?.[name]) body.fill = options.fill[name];\n\n const res = await transport(\n new Request(`${base}/admin/entities/${encodeURIComponent(name)}`, {\n method: \"PUT\",\n headers: { \"x-api-key\": options.key, \"content-type\": \"application/json\" },\n body: JSON.stringify(body),\n }),\n );\n const json = (await res.json().catch(() => null)) as\n | { status?: string; plan?: MigrationPlan; error?: string }\n | null;\n\n if (res.status === 200) applied.push(name);\n else if (res.status === 409 && json?.plan) review.push({ name, plan: json.plan });\n else throw errorFor(res.status, json?.error ?? `Push failed for '${name}' (${res.status}).`);\n }\n\n return { applied, review };\n}\n","// Config do projeto (raiz: `weave.config.ts`). Decisões ESTRUTURAIS, commitadas —\n// não env. URL e key são de ambiente/segredo, vêm de `WEAVE_URL`/`WEAVE_KEY`.\n// Puro (sem node) — pode ser importado de qualquer lugar.\n\nexport interface WeaveConfig {\n /**\n * Pasta onde o `weave gen` materializa tudo (`entities/`, `scopes/`, `index.ts`).\n * Default: `\"weave\"` na raiz do projeto. Ex.: `\"app/weave\"`.\n */\n dir?: string;\n}\n\n/** Helper tipado pro `weave.config.ts` (igual `defineConfig` do Vite/Drizzle). */\nexport function defineConfig(config: WeaveConfig = {}): WeaveConfig {\n return config;\n}\n\n/** Pasta padrão quando o config não define `dir`. */\nexport const DEFAULT_DIR = \"weave\";\n","import type { EntityIR, FieldIR } from \"@mauroandre/weave-core\";\nimport { errorFor } from \"./errors.js\";\nimport type { FetchLike } from \"./client.js\";\n\n// Scope-as-code: o dev escreve o scope por NOME (where Prisma-style + campos por\n// nome), e o `pushScopes` converte pro formato de STORAGE (por field-id, rename-proof)\n// e grava via `/admin/scopes`. Os conversores aqui são o inverso do enforcement\n// (`scope.ts → resolveFilter`): WhereInput-por-nome → path-Filter-por-id.\n\nexport type Verb = \"read\" | \"create\" | \"update\" | \"delete\";\n\nexport interface ScopeEntityRule {\n verbs: Verb[];\n /** Filtro de linhas (WhereInput, por NOME; valores podem ser `{ param: \"x\" }`). */\n where?: Record<string, unknown>;\n /** Projeção: caminhos por NOME (dot-path, ex.: `\"items.secret\"`). */\n fields?: { include?: string[]; exclude?: string[] };\n}\n\nexport interface ScopeDef {\n name: string;\n entities: Record<string, ScopeEntityRule>;\n}\n\n/** Helper tipado pro scope-as-code (igual `defineEntity`). */\nexport function defineScope(name: string, entities: Record<string, ScopeEntityRule>): ScopeDef {\n return { name, entities };\n}\n\nexport interface PushScopesOptions {\n url: string;\n key: string;\n fetch?: FetchLike;\n}\n\n// ── conversores (por nome → por id) ───────────────────────────────────────────\n\nconst isObj = (v: unknown): v is Record<string, unknown> => !!v && typeof v === \"object\" && !Array.isArray(v);\n\n/** Caminho de nomes (dot-path) → caminho de field-ids, descendo owned/reference. */\nfunction namePathToIds(entity: string, byName: Map<string, EntityIR>, dotPath: string): string[] {\n const ids: string[] = [];\n let fields = byName.get(entity)?.fields ?? {};\n const segs = dotPath.split(\".\");\n for (let i = 0; i < segs.length; i++) {\n const f = fields[segs[i]!];\n if (!f?.id) throw new Error(`scope: unknown field '${dotPath}' (em '${entity}').`);\n ids.push(f.id);\n if (i === segs.length - 1) break;\n if (f.kind === \"owned\") fields = f.shape ?? {};\n else if (f.kind === \"reference\") fields = byName.get(f.target)?.fields ?? {};\n else throw new Error(`scope: '${dotPath}' atravessa um escalar.`);\n }\n return ids;\n}\n\n/** Objeto de operador WhereInput → { op armazenado, value }. Inverso do `leafOp`. */\nfunction decodeOp(val: Record<string, unknown>): { op: string; value?: unknown } {\n const ilikeUnwrap = (s: unknown): { op: string; value: unknown } => {\n if (typeof s === \"string\" && s.startsWith(\"%\") && s.endsWith(\"%\")) return { op: \"contains\", value: s.slice(1, -1) };\n if (typeof s === \"string\" && s.endsWith(\"%\")) return { op: \"startsWith\", value: s.slice(0, -1) };\n return { op: \"contains\", value: s };\n };\n if (\"ilike\" in val) return ilikeUnwrap(val[\"ilike\"]);\n if (\"eq\" in val) return { op: \"equals\", value: val[\"eq\"] };\n if (\"ne\" in val) return { op: \"notEquals\", value: val[\"ne\"] };\n if (\"gt\" in val) return { op: \"gt\", value: val[\"gt\"] };\n if (\"gte\" in val) return { op: \"gte\", value: val[\"gte\"] };\n if (\"lt\" in val) return { op: \"lt\", value: val[\"lt\"] };\n if (\"lte\" in val) return { op: \"lte\", value: val[\"lte\"] };\n if (\"in\" in val) return { op: \"in\", value: val[\"in\"] };\n if (\"notIn\" in val) return { op: \"notIn\", value: val[\"notIn\"] };\n if (\"isNull\" in val) return { op: \"isEmpty\" };\n return { op: \"equals\", value: undefined };\n}\n\ntype ScopeFilter = unknown; // árvore path-based por-id (formato de storage)\n\n/** WhereInput (por nome) → path-Filter (por id). Desce `some` em to-many. */\nfunction whereToFilter(where: Record<string, unknown>, entity: string, byName: Map<string, EntityIR>): ScopeFilter {\n if (Array.isArray(where[\"and\"])) {\n return { and: (where[\"and\"] as Record<string, unknown>[]).map((w) => whereToFilter(w, entity, byName)) };\n }\n if (Array.isArray(where[\"or\"])) {\n return { or: (where[\"or\"] as Record<string, unknown>[]).map((w) => whereToFilter(w, entity, byName)) };\n }\n\n // Galho single-branch: desce até a folha (uma coluna), montando o id-path.\n const idPath: string[] = [];\n let cur: Record<string, unknown> = where;\n let fields = byName.get(entity)?.fields ?? {};\n for (let guard = 0; guard < 16; guard++) {\n const entry = Object.entries(cur)[0];\n if (!entry) break;\n const [key, val] = entry;\n const f: FieldIR | undefined = fields[key];\n if (!f?.id) throw new Error(`scope: campo '${key}' desconhecido em '${entity}'.`);\n idPath.push(f.id);\n\n if (f.kind === \"column\") {\n const opObj = f.array && isObj(val) && \"some\" in val ? (val[\"some\"] as Record<string, unknown>) : (val as Record<string, unknown>);\n const { op, value } = decodeOp(opObj);\n return value === undefined ? { path: idPath, op } : { path: idPath, op, value };\n }\n // travessia: owned/reference. `some` (to-many) é desembrulhado.\n fields = f.kind === \"owned\" ? (f.shape ?? {}) : (byName.get(f.target)?.fields ?? {});\n cur = isObj(val) && \"some\" in val ? (val[\"some\"] as Record<string, unknown>) : (val as Record<string, unknown>);\n }\n throw new Error(`scope: filtro inválido em '${entity}'.`);\n}\n\n/**\n * Empurra scopes-as-code: converte cada regra (where + fields por NOME) pro formato\n * por-id e grava via `PUT /admin/scopes/:name`. Busca os IRs das entidades pra\n * resolver os ids (rename-proof no storage).\n */\nexport async function pushScopes(\n scopes: Record<string, ScopeDef>,\n options: PushScopesOptions,\n): Promise<{ pushed: string[] }> {\n const transport: FetchLike = options.fetch ?? ((req) => globalThis.fetch(req));\n const base = options.url.replace(/\\/$/, \"\");\n\n // IRs de todas as entidades (pra resolver nome→id).\n const listRes = await transport(\n new Request(`${base}/admin/entities`, { method: \"GET\", headers: { \"x-api-key\": options.key } }),\n );\n const listJson = (await listRes.json().catch(() => null)) as { entities?: EntityIR[]; error?: string } | null;\n if (!listRes.ok || !listJson?.entities) {\n throw errorFor(listRes.status, listJson?.error ?? \"Failed to load entities for scope push.\");\n }\n const byName = new Map(listJson.entities.map((e) => [e.name, e] as const));\n\n const pushed: string[] = [];\n for (const def of Object.values(scopes)) {\n const entities: Record<string, unknown> = {};\n for (const [entity, rule] of Object.entries(def.entities)) {\n const rows = rule.where ? whereToFilter(rule.where, entity, byName) : null;\n let fields: { mode: \"include\" | \"exclude\"; paths: string[][] } | null = null;\n if (rule.fields?.include) {\n fields = { mode: \"include\", paths: rule.fields.include.map((p) => namePathToIds(entity, byName, p)) };\n } else if (rule.fields?.exclude) {\n fields = { mode: \"exclude\", paths: rule.fields.exclude.map((p) => namePathToIds(entity, byName, p)) };\n }\n entities[entity] = { verbs: rule.verbs, rows, fields };\n }\n\n const res = await transport(\n new Request(`${base}/admin/scopes/${encodeURIComponent(def.name)}`, {\n method: \"PUT\",\n headers: { \"x-api-key\": options.key, \"content-type\": \"application/json\" },\n body: JSON.stringify({ name: def.name, entities }),\n }),\n );\n if (!res.ok) {\n const j = (await res.json().catch(() => null)) as { error?: string } | null;\n throw errorFor(res.status, j?.error ?? `Push scope '${def.name}' failed (${res.status}).`);\n }\n pushed.push(def.name);\n }\n return { pushed };\n}\n","import type { EntityIR, FieldIR } from \"@mauroandre/weave-core\";\nimport { errorFor } from \"./errors.js\";\nimport type { FetchLike } from \"./client.js\";\n\n// Codegen: o estado do servidor (entidades + scopes, fonte da verdade) → source\n// `.ts` legível e commitável. Inverso do `toIR`/`pushScopes`. Puro (sem fs) — o\n// CLI escreve em disco. O `weave gen` reescreve a pasta `weave/` inteira a partir\n// daqui (overwrite cego): arquivos de entidade (com `$id`), de scope, os barrels\n// e o client configurado.\n\n// ── Entidade: IR → defineEntity ────────────────────────────────────────────────\n\ninterface GenCtx {\n builders: Set<string>; // construtores/helpers usados (text, owned, reference, array…)\n imports: Set<string>; // entidades-alvo de reference (pra importar)\n mirror: boolean; // owned com mirror — o builder não tem `mirror()` (limitação)\n withId: boolean; // emitir `.$id(...)` (rename-safe) — ligado pelo `weave gen`\n}\n\n/** Expressão-base do campo (sem o `.$id`). */\nfunction baseExpr(node: FieldIR, ctx: GenCtx, self: string): string {\n if (node.kind === \"column\") {\n ctx.builders.add(node.type);\n if (node.array) {\n ctx.builders.add(\"array\");\n let s = `array(${node.type}())`;\n if (node.notNull === false) s += \".nullable()\"; // arrays são notNull por padrão\n if (node.unique) s += \".unique()\";\n if (node.index) s += \".index()\";\n return s;\n }\n let s = `${node.type}()`;\n if (node.notNull) s += \".notNull()\";\n if (node.unique) s += \".unique()\";\n if (node.index) s += \".index()\";\n if (node.default !== undefined) s += `.default(${JSON.stringify(node.default)})`;\n return s;\n }\n if (node.kind === \"reference\") {\n ctx.builders.add(\"reference\");\n if (node.target !== self) ctx.imports.add(node.target);\n if (node.cardinality === \"many\") {\n ctx.builders.add(\"array\");\n return `reference(array(${node.target}))`;\n }\n return `reference(${node.target})${node.notNull ? \".notNull()\" : \"\"}`;\n }\n // owned\n if (node.mirror) ctx.mirror = true; // sem builder de mirror — gera o shape concreto (vazio se só mirror)\n ctx.builders.add(\"owned\");\n const inner = shapeSource(node.shape ?? {}, ctx, self);\n return node.array ? `owned(array({ ${inner} }))` : `owned({ ${inner} })`;\n}\n\nfunction fieldSource(node: FieldIR, ctx: GenCtx, self: string): string {\n const base = baseExpr(node, ctx, self);\n const id = ctx.withId && node.id ? `.$id(${JSON.stringify(node.id)})` : \"\";\n return base + id;\n}\n\nfunction shapeSource(fields: Record<string, FieldIR>, ctx: GenCtx, self: string): string {\n return Object.entries(fields)\n .map(([k, n]) => `${k}: ${fieldSource(n, ctx, self)}`)\n .join(\", \");\n}\n\nexport interface IrToSourceOptions {\n /** Emitir `.$id(...)` em cada campo (estável, rename-safe). Default: false. */\n withId?: boolean;\n}\n\n/** Gera o source `export default defineEntity(...)` de UMA entidade (com imports). */\nexport function irToSource(ir: EntityIR, options: IrToSourceOptions = {}): string {\n const ctx: GenCtx = { builders: new Set(), imports: new Set(), mirror: false, withId: options.withId ?? false };\n const body = Object.entries(ir.fields)\n .map(([k, n]) => ` ${k}: ${fieldSource(n, ctx, ir.name)},`)\n .join(\"\\n\");\n\n const builders = [\"defineEntity\", ...[...ctx.builders].sort()];\n const lines = [`import { ${builders.join(\", \")} } from \"@mauroandre/weave-sdk\";`];\n for (const t of [...ctx.imports].sort()) lines.push(`import ${t} from \"./${t}.js\";`);\n if (ctx.mirror) lines.push(`// ⚠ esta entidade usa mirror — gere/edite a forma à mão (o builder não tem mirror()).`);\n lines.push(\"\", `export default defineEntity(${JSON.stringify(ir.name)}, {`, body, \"});\", \"\");\n return lines.join(\"\\n\");\n}\n\n// ── Scope: storage por-id → defineScope por-nome ───────────────────────────────\n// Inverso do `pushScopes` (por-nome → por-id) e espelho do enforcement\n// (`app/api/scope.ts`: conditionToWhere/leafOp).\n\ninterface StoredCondition {\n path: string[];\n op: string;\n value?: unknown;\n}\ntype StoredFilter = StoredCondition | { and: StoredFilter[] } | { or: StoredFilter[] };\ninterface StoredProjection {\n mode: \"include\" | \"exclude\";\n paths: string[][];\n}\ninterface StoredRule {\n verbs: string[];\n rows: StoredFilter | null;\n fields: StoredProjection | null;\n}\ninterface StoredScope {\n name: string;\n entities: Record<string, StoredRule>;\n}\n\n/** Caminho de field-ids → caminho de nomes, descendo owned/reference. */\nfunction idPathToNames(entity: string, byName: Map<string, EntityIR>, idPath: string[]): string[] {\n const names: string[] = [];\n let fields = byName.get(entity)?.fields ?? {};\n for (let i = 0; i < idPath.length; i++) {\n const entry = Object.entries(fields).find(([, f]) => f.id === idPath[i]);\n if (!entry) throw new Error(`scope gen: field id '${idPath[i]}' não encontrado em '${entity}'.`);\n const [name, f] = entry;\n names.push(name);\n if (i === idPath.length - 1) break;\n if (f.kind === \"owned\") fields = f.shape ?? {};\n else if (f.kind === \"reference\") fields = byName.get(f.target)?.fields ?? {};\n else throw new Error(`scope gen: caminho atravessa um escalar em '${entity}'.`);\n }\n return names;\n}\n\n/** Operador de storage → objeto de operador WhereInput (espelha `leafOp`). */\nfunction opToWhere(op: string, value: unknown): Record<string, unknown> {\n const str = typeof value === \"string\";\n switch (op) {\n case \"contains\":\n return { ilike: str ? `%${value}%` : value };\n case \"startsWith\":\n return { ilike: str ? `${value}%` : value };\n case \"equals\":\n case \"on\":\n return { eq: value };\n case \"notEquals\":\n return { ne: value };\n case \"gt\":\n case \"gte\":\n case \"lt\":\n case \"lte\":\n return { [op]: value };\n case \"before\":\n return { lt: value };\n case \"after\":\n return { gt: value };\n case \"in\":\n return { in: value };\n case \"notIn\":\n return { notIn: value };\n case \"isTrue\":\n return { eq: true };\n case \"isFalse\":\n return { eq: false };\n case \"isEmpty\":\n return { isNull: true };\n default:\n return { eq: value };\n }\n}\n\n/** Nomes + op + valor → WhereInput aninhado (`some` em to-many) — espelha `conditionToWhere`. */\nfunction buildWhere(\n entity: string,\n byName: Map<string, EntityIR>,\n names: string[],\n op: string,\n value: unknown,\n): Record<string, unknown> {\n const rec = (fields: Record<string, FieldIR>, idx: number): Record<string, unknown> => {\n const seg = names[idx]!;\n const f = fields[seg];\n if (idx === names.length - 1) {\n const sc = opToWhere(op, value);\n const isArray = f?.kind === \"column\" && f.array === true;\n return { [seg]: isArray && op !== \"isEmpty\" ? { some: sc } : sc };\n }\n let next: Record<string, FieldIR> = {};\n let toMany = false;\n if (f?.kind === \"owned\") {\n next = f.shape ?? {};\n toMany = f.array === true;\n } else if (f?.kind === \"reference\") {\n next = byName.get(f.target)?.fields ?? {};\n toMany = f.cardinality === \"many\";\n }\n const inner = rec(next, idx + 1);\n return { [seg]: toMany ? { some: inner } : inner };\n };\n return rec(byName.get(entity)?.fields ?? {}, 0);\n}\n\n/** StoredFilter (por-id) → WhereInput (por-nome). */\nfunction filterToWhere(filter: StoredFilter, entity: string, byName: Map<string, EntityIR>): Record<string, unknown> {\n if (\"and\" in filter) return { and: filter.and.map((f) => filterToWhere(f, entity, byName)) };\n if (\"or\" in filter) return { or: filter.or.map((f) => filterToWhere(f, entity, byName)) };\n const names = idPathToNames(entity, byName, filter.path);\n return buildWhere(entity, byName, names, filter.op, filter.value);\n}\n\nconst IDENT = /^[A-Za-z_$][\\w$]*$/;\n\n/** Imprime um literal JS legível (chaves identifier sem aspas). */\nfunction lit(value: unknown, indent = 0): string {\n if (value === null) return \"null\";\n if (typeof value === \"string\") return JSON.stringify(value);\n if (typeof value === \"number\" || typeof value === \"boolean\") return String(value);\n if (Array.isArray(value)) return `[${value.map((v) => lit(v, indent)).join(\", \")}]`;\n if (typeof value === \"object\") {\n const entries = Object.entries(value as Record<string, unknown>);\n if (entries.length === 0) return \"{}\";\n const pad = \" \".repeat(indent + 1);\n const close = \" \".repeat(indent);\n const body = entries\n .map(([k, v]) => `${pad}${IDENT.test(k) ? k : JSON.stringify(k)}: ${lit(v, indent + 1)}`)\n .join(\",\\n\");\n return `{\\n${body},\\n${close}}`;\n }\n return JSON.stringify(value);\n}\n\n/** Gera o source `export default defineScope(...)` de UM scope (resolve id→nome). */\nexport function scopeToSource(scope: StoredScope, byName: Map<string, EntityIR>): string {\n const rules: Record<string, unknown> = {};\n for (const [entity, rule] of Object.entries(scope.entities)) {\n const out: Record<string, unknown> = { verbs: rule.verbs };\n if (rule.rows) out[\"where\"] = filterToWhere(rule.rows, entity, byName);\n if (rule.fields) {\n const paths = rule.fields.paths.map((p) => idPathToNames(entity, byName, p).join(\".\"));\n out[\"fields\"] = rule.fields.mode === \"include\" ? { include: paths } : { exclude: paths };\n }\n rules[entity] = out;\n }\n return [\n `import { defineScope } from \"@mauroandre/weave-sdk\";`,\n \"\",\n `export default defineScope(${JSON.stringify(scope.name)}, ${lit(rules)});`,\n \"\",\n ].join(\"\\n\");\n}\n\n// ── Barrels + client ───────────────────────────────────────────────────────────\n\n/** Barrel de re-exports nomeados (autocomplete por nome). */\nfunction barrelSource(names: string[]): string {\n return [\n `// GERADO por \\`weave gen\\` — não edite à mão.`,\n ...names.map((n) => `export { default as ${n} } from \"./${n}.js\";`),\n \"\",\n ].join(\"\\n\");\n}\n\n/** Client configurado (`weave/index.ts`) — lê WEAVE_URL/WEAVE_KEY do ambiente. */\nfunction clientSource(): string {\n return [\n `// GERADO por \\`weave gen\\` — não edite à mão. Uso server-side (a key é segredo).`,\n `import { createClient } from \"@mauroandre/weave-sdk\";`,\n `import * as entities from \"./entities/index.js\";`,\n \"\",\n `export const weave = createClient({`,\n ` url: process.env.WEAVE_URL!,`,\n ` key: process.env.WEAVE_KEY!,`,\n ` entities,`,\n `});`,\n \"\",\n ].join(\"\\n\");\n}\n\n// ── Orquestrador ───────────────────────────────────────────────────────────────\n\nexport interface GenOptions {\n url: string;\n key: string;\n fetch?: FetchLike;\n}\n\nexport interface GenProject {\n /** Caminho relativo (dentro da pasta `weave/`) → conteúdo. */\n files: Record<string, string>;\n entities: string[];\n scopes: string[];\n}\n\nasync function fetchJson<T>(transport: FetchLike, url: string, key: string, what: string): Promise<T> {\n const res = await transport(new Request(url, { method: \"GET\", headers: { \"x-api-key\": key } }));\n const json = (await res.json().catch(() => null)) as (T & { error?: string }) | null;\n if (!res.ok || !json) throw errorFor(res.status, json?.error ?? `Failed to load ${what}.`);\n return json;\n}\n\n/**\n * Busca o estado do servidor (entidades + scopes) e gera a árvore de arquivos da\n * pasta `weave/`: `entities/<name>.ts` (com `$id`) + barrel, `scopes/<name>.ts` +\n * barrel, e `index.ts` (client). O CLI limpa a pasta e escreve isto.\n */\nexport async function genProject(options: GenOptions): Promise<GenProject> {\n const transport: FetchLike = options.fetch ?? ((req) => globalThis.fetch(req));\n const base = options.url.replace(/\\/$/, \"\");\n\n const ents = await fetchJson<{ entities: EntityIR[] }>(transport, `${base}/admin/entities`, options.key, \"entities\");\n const scps = await fetchJson<{ scopes: StoredScope[] }>(transport, `${base}/admin/scopes`, options.key, \"scopes\");\n\n const byName = new Map(ents.entities.map((e) => [e.name, e] as const));\n const files: Record<string, string> = {};\n\n const entityNames: string[] = [];\n for (const ir of ents.entities) {\n files[`entities/${ir.name}.ts`] = irToSource(ir, { withId: true });\n entityNames.push(ir.name);\n }\n entityNames.sort();\n files[\"entities/index.ts\"] = barrelSource(entityNames);\n\n const scopeNames: string[] = [];\n for (const s of scps.scopes) {\n // Um scope que referencia um campo inexistente (ex.: deletado) não derruba o\n // gen inteiro — é pulado. O resto da pasta regenera normalmente.\n try {\n files[`scopes/${s.name}.ts`] = scopeToSource(s, byName);\n scopeNames.push(s.name);\n } catch {\n /* scope órfão — pulado */\n }\n }\n scopeNames.sort();\n files[\"scopes/index.ts\"] = barrelSource(scopeNames);\n\n files[\"index.ts\"] = clientSource();\n\n return { files, entities: entityNames, scopes: scopeNames };\n}\n\n// ── Legado (pull) — mantido pra compat; `gen` é o caminho principal agora ───────\n\nexport interface PullOptions {\n url: string;\n key: string;\n fetch?: FetchLike;\n}\n\n/** Puxa os IRs remotos e gera o source de cada entidade. Devolve `nome.ts → conteúdo`. */\nexport async function pullEntities(options: PullOptions): Promise<{ files: Record<string, string>; names: string[] }> {\n const transport: FetchLike = options.fetch ?? ((req) => globalThis.fetch(req));\n const base = options.url.replace(/\\/$/, \"\");\n const json = await fetchJson<{ entities: EntityIR[] }>(transport, `${base}/admin/entities`, options.key, \"entities\");\n\n const files: Record<string, string> = {};\n const names: string[] = [];\n for (const ir of json.entities) {\n files[`${ir.name}.ts`] = irToSource(ir);\n names.push(ir.name);\n }\n return { files, names: names.sort() };\n}\n"],"mappings":";AA0CO,IAAM,SAAN,MAAM,QAIX;AAAA,EAIA,YAAqB,QAAsB;AAAtB;AAAA,EAAuB;AAAA,EAAvB;AAAA;AAAA,EAGrB,UAA4C;AAC1C,WAAO,IAAI,QAAO,EAAE,GAAG,KAAK,QAAQ,SAAS,KAAK,CAAC;AAAA,EACrD;AAAA;AAAA,EAGA,WAA8C;AAC5C,WAAO,IAAI,QAAO,EAAE,GAAG,KAAK,QAAQ,SAAS,MAAM,CAAC;AAAA,EACtD;AAAA;AAAA,EAGA,QAAQ,OAA6C;AACnD,WAAO,IAAI,QAAO,EAAE,GAAG,KAAK,QAAQ,YAAY,MAAM,SAAS,MAAM,CAAC;AAAA,EACxE;AAAA;AAAA,EAGA,SAA+C;AAC7C,WAAO,IAAI,QAAO,EAAE,GAAG,KAAK,QAAQ,QAAQ,KAAK,CAAC;AAAA,EACpD;AAAA;AAAA,EAGA,QAA8C;AAC5C,WAAO,IAAI,QAAO,EAAE,GAAG,KAAK,QAAQ,OAAO,KAAK,CAAC;AAAA,EACnD;AAAA;AAAA,EAGA,IAAI,IAAkD;AACpD,WAAO,IAAI,QAAO,EAAE,GAAG,KAAK,QAAQ,GAAG,CAAC;AAAA,EAC1C;AACF;AAcO,SAAS,aAA+B,QAA2C;AACxF,SAAO,IAAI,OAA+B;AAAA,IACxC;AAAA,IACA,SAAS;AAAA,IACT,SAAS;AAAA,IACT,YAAY;AAAA,IACZ,QAAQ;AAAA,IACR,OAAO;AAAA,EACT,CAAC;AACH;;;ACzEO,IAAM,QAAN,MAAM,OAAiE;AAAA,EAE5E,YACW,OACA,aACA,SAEA,IACT;AALS;AACA;AACA;AAEA;AAAA,EACR;AAAA,EALQ;AAAA,EACA;AAAA,EACA;AAAA,EAEA;AAAA,EANF,OAAO;AAAA;AAAA,EAUhB,IAAI,IAAkC;AACpC,WAAO,IAAI,OAAM,KAAK,OAAO,KAAK,aAAa,KAAK,SAAS,EAAE;AAAA,EACjE;AACF;AAMO,IAAM,aAAN,MAA4C;AAAA,EAEjD,YAAqB,OAAe;AAAf;AAAA,EAAgB;AAAA,EAAhB;AAAA,EADZ,OAAO;AAElB;AAYO,SAAS,MACd,KACA,UAAwB,CAAC,GACY;AACrC,MAAI,eAAe,YAAY;AAC7B,WAAO,IAAI,MAAM,IAAI,OAAO,QAAQ,OAAO;AAAA,EAC7C;AACA,SAAO,IAAI,MAAM,KAAK,OAAO,OAAO;AACtC;;;ACxDO,IAAM,YAAN,MAAM,WAIX;AAAA,EAKA,YACW,QACA,aACA,WAEA,IACT;AALS;AACA;AACA;AAEA;AAAA,EACR;AAAA,EALQ;AAAA,EACA;AAAA,EACA;AAAA,EAEA;AAAA,EATF,OAAO;AAAA;AAAA,EAahB,UAA2C;AACzC,WAAO,IAAI,WAAgC,KAAK,QAAQ,KAAK,aAAa,MAAM,KAAK,EAAE;AAAA,EACzF;AAAA;AAAA,EAGA,IAAI,IAAiD;AACnD,WAAO,IAAI,WAAoC,KAAK,QAAQ,KAAK,aAAa,KAAK,WAAW,EAAE;AAAA,EAClG;AACF;AAMO,IAAM,iBAAN,MAAkE;AAAA,EAEvE,YAAqB,QAAiB;AAAjB;AAAA,EAAkB;AAAA,EAAlB;AAAA,EADZ,OAAO;AAElB;AAUO,SAAS,UACd,KACqE;AACrE,MAAI,eAAe,gBAAgB;AACjC,WAAO,IAAI,UAAU,IAAI,QAAQ,QAAQ,KAAK;AAAA,EAChD;AACA,SAAO,IAAI,UAAU,KAAK,OAAO,KAAK;AACxC;;;ACJO,SAAS,aAAkB;AAChC,SAAO,CAAuB,SAA+C;AAAA,IAC3E,GAAG;AAAA;AAAA,IAEH,QAAQ;AAAA,EACV;AACF;;;ACnDO,IAAM,OAAO,WAAmB,EAAE,EAAE,MAAM,QAAQ,SAAS,YAAY,KAAK,IAAI,SAAS,SAAS,CAAC;AACnG,IAAM,OAAO,WAAmB,EAAE,EAAE,MAAM,QAAQ,SAAS,WAAW,KAAK,IAAI,SAAS,SAAS,CAAC;AAClG,IAAM,OAAO,WAAmB,EAAE,EAAE,MAAM,QAAQ,SAAS,UAAU,KAAK,IAAI,SAAS,SAAS,CAAC;AACjG,IAAM,UAAU,WAAmB,EAAE,EAAE,MAAM,WAAW,SAAS,WAAW,KAAK,MAAM,SAAS,SAAS,CAAC;AAC1G,IAAM,SAAS,WAAmB,EAAE,EAAE,MAAM,UAAU,SAAS,QAAQ,KAAK,KAAK,SAAS,SAAS,CAAC;AACpG,IAAM,SAAS,WAAmB,EAAE,EAAE,MAAM,UAAU,SAAS,oBAAoB,KAAK,KAAK,SAAS,SAAS,CAAC;AAGhH,IAAM,OAAO,WAAmB,EAAE,EAAE,MAAM,QAAQ,SAAS,QAAQ,KAAK,IAAI,SAAS,SAAS,CAAC;AAC/F,IAAM,UAAU,WAAmB,EAAE,EAAE,MAAM,WAAW,SAAS,WAAW,KAAK,MAAM,SAAS,SAAS,CAAC;AAC1G,IAAM,SAAS,WAAmB,EAAE,EAAE,MAAM,UAAU,SAAS,QAAQ,KAAK,MAAM,SAAS,SAAS,CAAC;AAGrG,IAAM,cAAc,WAAiB,EAAE,EAAE,MAAM,eAAe,SAAS,4BAA4B,KAAK,MAAM,SAAS,OAAO,CAAC;AAC/H,IAAM,YAAY,WAAiB,EAAE,EAAE,MAAM,aAAa,SAAS,aAAa,KAAK,MAAM,SAAS,OAAO,CAAC;AAC5G,IAAM,OAAO,WAAiB,EAAE,EAAE,MAAM,QAAQ,SAAS,QAAQ,KAAK,MAAM,SAAS,OAAO,CAAC;AAC7F,IAAM,OAAO,WAAmB,EAAE,EAAE,MAAM,QAAQ,SAAS,QAAQ,KAAK,MAAM,SAAS,SAAS,CAAC;AACjG,IAAM,WAAW,WAAmB,EAAE,EAAE,MAAM,YAAY,SAAS,YAAY,KAAK,MAAM,SAAS,SAAS,CAAC;AAG7G,IAAM,OAAO,WAAoB,EAAE,EAAE,MAAM,QAAQ,SAAS,WAAW,KAAK,IAAI,SAAS,UAAU,CAAC;AAGpG,IAAM,OAAO,WAAmB,EAAE,EAAE,MAAM,QAAQ,SAAS,QAAQ,KAAK,MAAM,SAAS,SAAS,CAAC;AAGjG,IAAM,OAAO,WAAoB,EAAE,EAAE,MAAM,QAAQ,SAAS,QAAQ,KAAK,KAAK,SAAS,UAAU,CAAC;AAClG,IAAM,QAAQ,WAAoB,EAAE,EAAE,MAAM,SAAS,SAAS,SAAS,KAAK,MAAM,SAAS,UAAU,CAAC;AAGtG,IAAM,QAAQ,WAAuB,EAAE,EAAE,MAAM,SAAS,SAAS,SAAS,KAAK,IAAI,SAAS,aAAa,CAAC;;;ACvC1G,IAAM,UAAU;AAAA,EACrB;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF;AAKO,IAAM,WAA8B,OAAO,OAAO,OAAO;AAGzD,IAAM,SAAsC,IAAI;AAAA,EACrD,SAAS,IAAI,CAAC,MAAM,CAAC,EAAE,MAAM,CAAC,CAAC;AACjC;AAGO,IAAM,QAAqC,IAAI;AAAA,EACpD,SAAS,IAAI,CAAC,MAAM,CAAC,EAAE,KAAK,CAAC,CAAC;AAChC;;;ACjCO,IAAMA,QAAO,MAAM,aAAa,QAAQ,IAAI;AAC5C,IAAMC,QAAO,MAAM,aAAa,QAAQ,IAAI;AAC5C,IAAMC,QAAO,MAAM,aAAa,QAAQ,IAAI;AAC5C,IAAMC,WAAU,MAAM,aAAa,QAAQ,OAAO;AAClD,IAAMC,UAAS,MAAM,aAAa,QAAQ,MAAM;AAChD,IAAMC,UAAS,MAAM,aAAa,QAAQ,MAAM;AAGhD,IAAMC,QAAO,MAAM,aAAa,QAAQ,IAAI;AAC5C,IAAMC,WAAU,MAAM,aAAa,QAAQ,OAAO;AAClD,IAAMC,UAAS,MAAM,aAAa,QAAQ,MAAM;AAGhD,IAAMC,eAAc,MAAM,aAAa,QAAQ,WAAW;AAC1D,IAAMC,aAAY,MAAM,aAAa,QAAQ,SAAS;AACtD,IAAMC,QAAO,MAAM,aAAa,QAAQ,IAAI;AAC5C,IAAMC,QAAO,MAAM,aAAa,QAAQ,IAAI;AAC5C,IAAMC,YAAW,MAAM,aAAa,QAAQ,QAAQ;AAGpD,IAAMC,QAAO,MAAM,aAAa,QAAQ,IAAI;AAG5C,IAAMC,QAAO,MAAM,aAAa,QAAQ,IAAI;AAG5C,IAAMC,QAAO,MAAM,aAAa,QAAQ,IAAI;AAC5C,IAAMC,SAAQ,MAAM,aAAa,QAAQ,KAAK;AAG9C,IAAMC,SAAQ,MAAM,aAAa,QAAQ,KAAK;AAiB9C,SAAS,MACd,KACsG;AACtG,MAAI,eAAe,QAAQ;AACzB,WAAO,IAAI,OAA8B;AAAA,MACvC,QAAQ,IAAI,OAAO;AAAA,MACnB,SAAS;AAAA,MACT,SAAS;AAAA,MACT,YAAY;AAAA,MACZ,SAAS,CAAC;AAAA,MACV,QAAQ;AAAA,MACR,OAAO;AAAA,IACT,CAAC;AAAA,EACH;AAEA,QAAM,YAAY;AAClB,MAAI,OAAO,UAAU,SAAS,YAAY,OAAO,UAAU,YAAY,UAAU;AAC/E,WAAO,IAAI,eAAe,GAAkC;AAAA,EAC9D;AACA,SAAO,IAAI,WAAW,GAAiB;AACzC;;;AC8LO,SAAS,aACd,MACA,SACuB;AACvB,SAAO,EAAE,MAAM,QAAQ;AACzB;;;AChQO,SAAS,KAAK,QAA+C;AAClE,SAAO,EAAE,WAAW,GAAG,MAAM,OAAO,MAAM,QAAQ,UAAU,OAAO,OAAO,EAAE;AAC9E;AAEA,SAAS,UAAU,OAA0D;AAC3E,QAAM,MAA+B,CAAC;AACtC,aAAW,CAAC,KAAK,IAAI,KAAK,OAAO,QAAQ,KAAK,EAAG,KAAI,GAAG,IAAI,SAAS,IAAI;AACzE,SAAO;AACT;AAEA,SAAS,SAAS,MAAoC;AACpD,MAAI,gBAAgB,QAAQ;AAC1B,UAAM,IAAI,KAAK;AACf,UAAM,KAAe,EAAE,MAAM,UAAU,MAAM,EAAE,OAAO,KAAK;AAC3D,QAAI,EAAE,GAAI,IAAG,KAAK,EAAE;AACpB,QAAI,EAAE,QAAS,IAAG,QAAQ;AAC1B,QAAI,EAAE,QAAS,IAAG,UAAU;AAC5B,QAAI,EAAE,WAAY,IAAG,UAAU,EAAE;AACjC,QAAI,EAAE,OAAQ,IAAG,SAAS;AAC1B,QAAI,EAAE,MAAO,IAAG,QAAQ;AACxB,WAAO;AAAA,EACT;AACA,MAAI,gBAAgB,WAAW;AAC7B,UAAM,KAAkB;AAAA,MACtB,MAAM;AAAA,MACN,QAAQ,KAAK,OAAO;AAAA,MACpB,aAAa,KAAK;AAAA,IACpB;AACA,QAAI,KAAK,GAAI,IAAG,KAAK,KAAK;AAC1B,QAAI,KAAK,UAAW,IAAG,UAAU;AACjC,WAAO;AAAA,EACT;AACA,MAAI,gBAAgB,OAAO;AACzB,UAAM,KAAc;AAAA,MAClB,MAAM;AAAA,MACN,OAAO,KAAK,gBAAgB;AAAA,MAC5B,OAAO,UAAU,KAAK,KAAK;AAAA,IAC7B;AACA,QAAI,KAAK,GAAI,IAAG,KAAK,KAAK;AAC1B,QAAI,KAAK,QAAQ,UAAU,OAAW,IAAG,QAAQ,KAAK,QAAQ;AAC9D,WAAO;AAAA,EACT;AACA,QAAM,IAAI,MAAM,4EAAoE;AACtF;;;AC5DO,IAAM,aAAN,cAAyB,MAAM;AAAA,EACpC,YACE,SACS,QACT;AACA,UAAM,OAAO;AAFJ;AAGT,SAAK,OAAO;AAAA,EACd;AAAA,EAJW;AAKb;AAGO,IAAM,iBAAN,cAA6B,WAAW;AAAA,EAC7C,YAAY,SAAiB;AAC3B,UAAM,SAAS,GAAG;AAClB,SAAK,OAAO;AAAA,EACd;AACF;AAGO,IAAM,kBAAN,cAA8B,WAAW;AAAA,EAC9C,YAAY,SAAiB;AAC3B,UAAM,SAAS,GAAG;AAClB,SAAK,OAAO;AAAA,EACd;AACF;AAGO,IAAM,qBAAN,cAAiC,WAAW;AAAA,EACjD,YAAY,SAAiB;AAC3B,UAAM,SAAS,GAAG;AAClB,SAAK,OAAO;AAAA,EACd;AACF;AAGO,IAAM,uBAAN,cAAmC,WAAW;AAAA,EACnD,YAAY,SAAiB;AAC3B,UAAM,SAAS,GAAG;AAClB,SAAK,OAAO;AAAA,EACd;AACF;AAGO,SAAS,SAAS,QAAgB,SAA6B;AACpE,UAAQ,QAAQ;AAAA,IACd,KAAK;AACH,aAAO,IAAI,eAAe,OAAO;AAAA,IACnC,KAAK;AACH,aAAO,IAAI,gBAAgB,OAAO;AAAA,IACpC,KAAK;AACH,aAAO,IAAI,mBAAmB,OAAO;AAAA,IACvC,KAAK;AACH,aAAO,IAAI,qBAAqB,OAAO;AAAA,IACzC;AACE,aAAO,IAAI,WAAW,SAAS,MAAM;AAAA,EACzC;AACF;;;AChBA,eAAe,QAAQ,WAAsB,MAAc,KAAa,MAAwC;AAC9G,QAAM,MAAM,MAAM;AAAA,IAChB,IAAI,QAAQ,GAAG,IAAI,mBAAmB,mBAAmB,IAAI,CAAC,IAAI,EAAE,QAAQ,OAAO,SAAS,EAAE,aAAa,IAAI,EAAE,CAAC;AAAA,EACpH;AACA,MAAI,CAAC,IAAI,GAAI,QAAO;AACpB,SAAQ,MAAM,IAAI,KAAK,EAAE,MAAM,MAAM,IAAI;AAC3C;AAGA,SAAS,OAAO,IAA2B;AACzC,QAAM,OAAO,oBAAI,IAAY;AAC7B,QAAM,OAAO,CAAC,WAA0C;AACtD,eAAW,QAAQ,OAAO,OAAO,MAAM,GAAG;AACxC,UAAI,KAAK,SAAS,YAAa,MAAK,IAAI,KAAK,MAAM;AAAA,eAC1C,KAAK,SAAS,SAAS;AAC9B,YAAI,KAAK,OAAQ,MAAK,IAAI,KAAK,MAAM;AACrC,YAAI,KAAK,MAAO,MAAK,KAAK,KAAK;AAAA,MACjC;AAAA,IACF;AAAA,EACF;AACA,OAAK,GAAG,MAAM;AACd,SAAO;AACT;AAUA,eAAsB,aACpB,UACA,SACqB;AACrB,QAAM,YAAuB,QAAQ,UAAU,CAAC,QAAQ,WAAW,MAAM,GAAG;AAC5E,QAAM,OAAO,QAAQ,IAAI,QAAQ,OAAO,EAAE;AAE1C,QAAM,MAAM,OAAO,OAAO,QAAQ,EAAE,IAAI,CAAC,OAAO,EAAE,MAAM,EAAE,MAAM,IAAI,KAAK,CAAC,EAAE,EAAE;AAC9E,QAAMC,UAAS,IAAI,IAAI,IAAI,IAAI,CAAC,MAAM,CAAC,EAAE,MAAM,CAAC,CAAU,CAAC;AAG3D,QAAM,UAA4C,CAAC;AACnD,QAAM,OAAO,oBAAI,IAAY;AAC7B,QAAM,QAAQ,CAAC,MAA4C;AACzD,QAAI,KAAK,IAAI,EAAE,IAAI,EAAG;AACtB,SAAK,IAAI,EAAE,IAAI;AACf,eAAW,OAAO,OAAO,EAAE,EAAE,GAAG;AAC9B,YAAM,IAAIA,QAAO,IAAI,GAAG;AACxB,UAAI,EAAG,OAAM,CAAC;AAAA,IAChB;AACA,YAAQ,KAAK,CAAC;AAAA,EAChB;AACA,aAAW,KAAK,IAAK,OAAM,CAAC;AAE5B,QAAM,UAAoB,CAAC;AAC3B,QAAM,SAAkD,CAAC;AAEzD,aAAW,EAAE,MAAM,GAAG,KAAK,SAAS;AAElC,UAAM,YAAY,QAAQ,UAAU,IAAI;AACxC,QAAI,aAAa,OAAO,KAAK,SAAS,EAAE,SAAS,GAAG;AAClD,YAAM,WAAW,MAAM,QAAQ,WAAW,MAAM,QAAQ,KAAK,IAAI;AACjE,UAAI,UAAU;AACZ,cAAM,cAAc,oBAAI,IAAoB;AAC5C,mBAAW,CAAC,OAAO,KAAK,KAAK,OAAO,QAAQ,SAAS,MAAM,EAAG,KAAI,MAAM,GAAI,aAAY,IAAI,OAAO,MAAM,EAAE;AAC3G,mBAAW,CAAC,SAAS,OAAO,KAAK,OAAO,QAAQ,SAAS,GAAG;AAC1D,gBAAM,KAAK,YAAY,IAAI,OAAO;AAClC,gBAAM,SAAS,GAAG,OAAO,OAAO;AAChC,cAAI,MAAM,OAAQ,IAAG,SAAS,EAAE,GAAG,GAAG,QAAQ,CAAC,OAAO,GAAG,EAAE,GAAG,QAAQ,GAAG,EAAE;AAAA,QAC7E;AAAA,MACF;AAAA,IACF;AAEA,UAAM,OAAgC,EAAE,GAAG;AAC3C,QAAI,QAAQ,UAAU,IAAI,EAAG,MAAK,UAAU,QAAQ,QAAQ,IAAI;AAChE,QAAI,QAAQ,OAAO,IAAI,EAAG,MAAK,OAAO,QAAQ,KAAK,IAAI;AAEvD,UAAM,MAAM,MAAM;AAAA,MAChB,IAAI,QAAQ,GAAG,IAAI,mBAAmB,mBAAmB,IAAI,CAAC,IAAI;AAAA,QAChE,QAAQ;AAAA,QACR,SAAS,EAAE,aAAa,QAAQ,KAAK,gBAAgB,mBAAmB;AAAA,QACxE,MAAM,KAAK,UAAU,IAAI;AAAA,MAC3B,CAAC;AAAA,IACH;AACA,UAAMC,QAAQ,MAAM,IAAI,KAAK,EAAE,MAAM,MAAM,IAAI;AAI/C,QAAI,IAAI,WAAW,IAAK,SAAQ,KAAK,IAAI;AAAA,aAChC,IAAI,WAAW,OAAOA,OAAM,KAAM,QAAO,KAAK,EAAE,MAAM,MAAMA,MAAK,KAAK,CAAC;AAAA,QAC3E,OAAM,SAAS,IAAI,QAAQA,OAAM,SAAS,oBAAoB,IAAI,MAAM,IAAI,MAAM,IAAI;AAAA,EAC7F;AAEA,SAAO,EAAE,SAAS,OAAO;AAC3B;;;AC9HO,SAAS,aAAa,SAAsB,CAAC,GAAgB;AAClE,SAAO;AACT;AAGO,IAAM,cAAc;;;ACOpB,SAAS,YAAY,MAAc,UAAqD;AAC7F,SAAO,EAAE,MAAM,SAAS;AAC1B;AAUA,IAAM,QAAQ,CAAC,MAA6C,CAAC,CAAC,KAAK,OAAO,MAAM,YAAY,CAAC,MAAM,QAAQ,CAAC;AAG5G,SAAS,cAAc,QAAgBC,SAA+B,SAA2B;AAC/F,QAAM,MAAgB,CAAC;AACvB,MAAI,SAASA,QAAO,IAAI,MAAM,GAAG,UAAU,CAAC;AAC5C,QAAM,OAAO,QAAQ,MAAM,GAAG;AAC9B,WAAS,IAAI,GAAG,IAAI,KAAK,QAAQ,KAAK;AACpC,UAAM,IAAI,OAAO,KAAK,CAAC,CAAE;AACzB,QAAI,CAAC,GAAG,GAAI,OAAM,IAAI,MAAM,yBAAyB,OAAO,UAAU,MAAM,KAAK;AACjF,QAAI,KAAK,EAAE,EAAE;AACb,QAAI,MAAM,KAAK,SAAS,EAAG;AAC3B,QAAI,EAAE,SAAS,QAAS,UAAS,EAAE,SAAS,CAAC;AAAA,aACpC,EAAE,SAAS,YAAa,UAASA,QAAO,IAAI,EAAE,MAAM,GAAG,UAAU,CAAC;AAAA,QACtE,OAAM,IAAI,MAAM,WAAW,OAAO,yBAAyB;AAAA,EAClE;AACA,SAAO;AACT;AAGA,SAAS,SAAS,KAA+D;AAC/E,QAAM,cAAc,CAAC,MAA+C;AAClE,QAAI,OAAO,MAAM,YAAY,EAAE,WAAW,GAAG,KAAK,EAAE,SAAS,GAAG,EAAG,QAAO,EAAE,IAAI,YAAY,OAAO,EAAE,MAAM,GAAG,EAAE,EAAE;AAClH,QAAI,OAAO,MAAM,YAAY,EAAE,SAAS,GAAG,EAAG,QAAO,EAAE,IAAI,cAAc,OAAO,EAAE,MAAM,GAAG,EAAE,EAAE;AAC/F,WAAO,EAAE,IAAI,YAAY,OAAO,EAAE;AAAA,EACpC;AACA,MAAI,WAAW,IAAK,QAAO,YAAY,IAAI,OAAO,CAAC;AACnD,MAAI,QAAQ,IAAK,QAAO,EAAE,IAAI,UAAU,OAAO,IAAI,IAAI,EAAE;AACzD,MAAI,QAAQ,IAAK,QAAO,EAAE,IAAI,aAAa,OAAO,IAAI,IAAI,EAAE;AAC5D,MAAI,QAAQ,IAAK,QAAO,EAAE,IAAI,MAAM,OAAO,IAAI,IAAI,EAAE;AACrD,MAAI,SAAS,IAAK,QAAO,EAAE,IAAI,OAAO,OAAO,IAAI,KAAK,EAAE;AACxD,MAAI,QAAQ,IAAK,QAAO,EAAE,IAAI,MAAM,OAAO,IAAI,IAAI,EAAE;AACrD,MAAI,SAAS,IAAK,QAAO,EAAE,IAAI,OAAO,OAAO,IAAI,KAAK,EAAE;AACxD,MAAI,QAAQ,IAAK,QAAO,EAAE,IAAI,MAAM,OAAO,IAAI,IAAI,EAAE;AACrD,MAAI,WAAW,IAAK,QAAO,EAAE,IAAI,SAAS,OAAO,IAAI,OAAO,EAAE;AAC9D,MAAI,YAAY,IAAK,QAAO,EAAE,IAAI,UAAU;AAC5C,SAAO,EAAE,IAAI,UAAU,OAAO,OAAU;AAC1C;AAKA,SAAS,cAAc,OAAgC,QAAgBA,SAA4C;AACjH,MAAI,MAAM,QAAQ,MAAM,KAAK,CAAC,GAAG;AAC/B,WAAO,EAAE,KAAM,MAAM,KAAK,EAAgC,IAAI,CAAC,MAAM,cAAc,GAAG,QAAQA,OAAM,CAAC,EAAE;AAAA,EACzG;AACA,MAAI,MAAM,QAAQ,MAAM,IAAI,CAAC,GAAG;AAC9B,WAAO,EAAE,IAAK,MAAM,IAAI,EAAgC,IAAI,CAAC,MAAM,cAAc,GAAG,QAAQA,OAAM,CAAC,EAAE;AAAA,EACvG;AAGA,QAAM,SAAmB,CAAC;AAC1B,MAAI,MAA+B;AACnC,MAAI,SAASA,QAAO,IAAI,MAAM,GAAG,UAAU,CAAC;AAC5C,WAAS,QAAQ,GAAG,QAAQ,IAAI,SAAS;AACvC,UAAM,QAAQ,OAAO,QAAQ,GAAG,EAAE,CAAC;AACnC,QAAI,CAAC,MAAO;AACZ,UAAM,CAAC,KAAK,GAAG,IAAI;AACnB,UAAM,IAAyB,OAAO,GAAG;AACzC,QAAI,CAAC,GAAG,GAAI,OAAM,IAAI,MAAM,iBAAiB,GAAG,sBAAsB,MAAM,IAAI;AAChF,WAAO,KAAK,EAAE,EAAE;AAEhB,QAAI,EAAE,SAAS,UAAU;AACvB,YAAM,QAAQ,EAAE,SAAS,MAAM,GAAG,KAAK,UAAU,MAAO,IAAI,MAAM,IAAiC;AACnG,YAAM,EAAE,IAAI,MAAM,IAAI,SAAS,KAAK;AACpC,aAAO,UAAU,SAAY,EAAE,MAAM,QAAQ,GAAG,IAAI,EAAE,MAAM,QAAQ,IAAI,MAAM;AAAA,IAChF;AAEA,aAAS,EAAE,SAAS,UAAW,EAAE,SAAS,CAAC,IAAMA,QAAO,IAAI,EAAE,MAAM,GAAG,UAAU,CAAC;AAClF,UAAM,MAAM,GAAG,KAAK,UAAU,MAAO,IAAI,MAAM,IAAiC;AAAA,EAClF;AACA,QAAM,IAAI,MAAM,iCAA8B,MAAM,IAAI;AAC1D;AAOA,eAAsB,WACpB,QACA,SAC+B;AAC/B,QAAM,YAAuB,QAAQ,UAAU,CAAC,QAAQ,WAAW,MAAM,GAAG;AAC5E,QAAM,OAAO,QAAQ,IAAI,QAAQ,OAAO,EAAE;AAG1C,QAAM,UAAU,MAAM;AAAA,IACpB,IAAI,QAAQ,GAAG,IAAI,mBAAmB,EAAE,QAAQ,OAAO,SAAS,EAAE,aAAa,QAAQ,IAAI,EAAE,CAAC;AAAA,EAChG;AACA,QAAM,WAAY,MAAM,QAAQ,KAAK,EAAE,MAAM,MAAM,IAAI;AACvD,MAAI,CAAC,QAAQ,MAAM,CAAC,UAAU,UAAU;AACtC,UAAM,SAAS,QAAQ,QAAQ,UAAU,SAAS,yCAAyC;AAAA,EAC7F;AACA,QAAMA,UAAS,IAAI,IAAI,SAAS,SAAS,IAAI,CAAC,MAAM,CAAC,EAAE,MAAM,CAAC,CAAU,CAAC;AAEzE,QAAM,SAAmB,CAAC;AAC1B,aAAW,OAAO,OAAO,OAAO,MAAM,GAAG;AACvC,UAAM,WAAoC,CAAC;AAC3C,eAAW,CAAC,QAAQ,IAAI,KAAK,OAAO,QAAQ,IAAI,QAAQ,GAAG;AACzD,YAAM,OAAO,KAAK,QAAQ,cAAc,KAAK,OAAO,QAAQA,OAAM,IAAI;AACtE,UAAI,SAAoE;AACxE,UAAI,KAAK,QAAQ,SAAS;AACxB,iBAAS,EAAE,MAAM,WAAW,OAAO,KAAK,OAAO,QAAQ,IAAI,CAAC,MAAM,cAAc,QAAQA,SAAQ,CAAC,CAAC,EAAE;AAAA,MACtG,WAAW,KAAK,QAAQ,SAAS;AAC/B,iBAAS,EAAE,MAAM,WAAW,OAAO,KAAK,OAAO,QAAQ,IAAI,CAAC,MAAM,cAAc,QAAQA,SAAQ,CAAC,CAAC,EAAE;AAAA,MACtG;AACA,eAAS,MAAM,IAAI,EAAE,OAAO,KAAK,OAAO,MAAM,OAAO;AAAA,IACvD;AAEA,UAAM,MAAM,MAAM;AAAA,MAChB,IAAI,QAAQ,GAAG,IAAI,iBAAiB,mBAAmB,IAAI,IAAI,CAAC,IAAI;AAAA,QAClE,QAAQ;AAAA,QACR,SAAS,EAAE,aAAa,QAAQ,KAAK,gBAAgB,mBAAmB;AAAA,QACxE,MAAM,KAAK,UAAU,EAAE,MAAM,IAAI,MAAM,SAAS,CAAC;AAAA,MACnD,CAAC;AAAA,IACH;AACA,QAAI,CAAC,IAAI,IAAI;AACX,YAAM,IAAK,MAAM,IAAI,KAAK,EAAE,MAAM,MAAM,IAAI;AAC5C,YAAM,SAAS,IAAI,QAAQ,GAAG,SAAS,eAAe,IAAI,IAAI,aAAa,IAAI,MAAM,IAAI;AAAA,IAC3F;AACA,WAAO,KAAK,IAAI,IAAI;AAAA,EACtB;AACA,SAAO,EAAE,OAAO;AAClB;;;AC7IA,SAAS,SAAS,MAAe,KAAa,MAAsB;AAClE,MAAI,KAAK,SAAS,UAAU;AAC1B,QAAI,SAAS,IAAI,KAAK,IAAI;AAC1B,QAAI,KAAK,OAAO;AACd,UAAI,SAAS,IAAI,OAAO;AACxB,UAAIC,KAAI,SAAS,KAAK,IAAI;AAC1B,UAAI,KAAK,YAAY,MAAO,CAAAA,MAAK;AACjC,UAAI,KAAK,OAAQ,CAAAA,MAAK;AACtB,UAAI,KAAK,MAAO,CAAAA,MAAK;AACrB,aAAOA;AAAA,IACT;AACA,QAAI,IAAI,GAAG,KAAK,IAAI;AACpB,QAAI,KAAK,QAAS,MAAK;AACvB,QAAI,KAAK,OAAQ,MAAK;AACtB,QAAI,KAAK,MAAO,MAAK;AACrB,QAAI,KAAK,YAAY,OAAW,MAAK,YAAY,KAAK,UAAU,KAAK,OAAO,CAAC;AAC7E,WAAO;AAAA,EACT;AACA,MAAI,KAAK,SAAS,aAAa;AAC7B,QAAI,SAAS,IAAI,WAAW;AAC5B,QAAI,KAAK,WAAW,KAAM,KAAI,QAAQ,IAAI,KAAK,MAAM;AACrD,QAAI,KAAK,gBAAgB,QAAQ;AAC/B,UAAI,SAAS,IAAI,OAAO;AACxB,aAAO,mBAAmB,KAAK,MAAM;AAAA,IACvC;AACA,WAAO,aAAa,KAAK,MAAM,IAAI,KAAK,UAAU,eAAe,EAAE;AAAA,EACrE;AAEA,MAAI,KAAK,OAAQ,KAAI,SAAS;AAC9B,MAAI,SAAS,IAAI,OAAO;AACxB,QAAM,QAAQ,YAAY,KAAK,SAAS,CAAC,GAAG,KAAK,IAAI;AACrD,SAAO,KAAK,QAAQ,iBAAiB,KAAK,SAAS,WAAW,KAAK;AACrE;AAEA,SAAS,YAAY,MAAe,KAAa,MAAsB;AACrE,QAAM,OAAO,SAAS,MAAM,KAAK,IAAI;AACrC,QAAM,KAAK,IAAI,UAAU,KAAK,KAAK,QAAQ,KAAK,UAAU,KAAK,EAAE,CAAC,MAAM;AACxE,SAAO,OAAO;AAChB;AAEA,SAAS,YAAY,QAAiC,KAAa,MAAsB;AACvF,SAAO,OAAO,QAAQ,MAAM,EACzB,IAAI,CAAC,CAAC,GAAG,CAAC,MAAM,GAAG,CAAC,KAAK,YAAY,GAAG,KAAK,IAAI,CAAC,EAAE,EACpD,KAAK,IAAI;AACd;AAQO,SAAS,WAAW,IAAc,UAA6B,CAAC,GAAW;AAChF,QAAM,MAAc,EAAE,UAAU,oBAAI,IAAI,GAAG,SAAS,oBAAI,IAAI,GAAG,QAAQ,OAAO,QAAQ,QAAQ,UAAU,MAAM;AAC9G,QAAM,OAAO,OAAO,QAAQ,GAAG,MAAM,EAClC,IAAI,CAAC,CAAC,GAAG,CAAC,MAAM,KAAK,CAAC,KAAK,YAAY,GAAG,KAAK,GAAG,IAAI,CAAC,GAAG,EAC1D,KAAK,IAAI;AAEZ,QAAM,WAAW,CAAC,gBAAgB,GAAG,CAAC,GAAG,IAAI,QAAQ,EAAE,KAAK,CAAC;AAC7D,QAAM,QAAQ,CAAC,YAAY,SAAS,KAAK,IAAI,CAAC,kCAAkC;AAChF,aAAW,KAAK,CAAC,GAAG,IAAI,OAAO,EAAE,KAAK,EAAG,OAAM,KAAK,UAAU,CAAC,YAAY,CAAC,OAAO;AACnF,MAAI,IAAI,OAAQ,OAAM,KAAK,2GAAwF;AACnH,QAAM,KAAK,IAAI,+BAA+B,KAAK,UAAU,GAAG,IAAI,CAAC,OAAO,MAAM,OAAO,EAAE;AAC3F,SAAO,MAAM,KAAK,IAAI;AACxB;AA2BA,SAAS,cAAc,QAAgBC,SAA+B,QAA4B;AAChG,QAAM,QAAkB,CAAC;AACzB,MAAI,SAASA,QAAO,IAAI,MAAM,GAAG,UAAU,CAAC;AAC5C,WAAS,IAAI,GAAG,IAAI,OAAO,QAAQ,KAAK;AACtC,UAAM,QAAQ,OAAO,QAAQ,MAAM,EAAE,KAAK,CAAC,CAAC,EAAEC,EAAC,MAAMA,GAAE,OAAO,OAAO,CAAC,CAAC;AACvE,QAAI,CAAC,MAAO,OAAM,IAAI,MAAM,wBAAwB,OAAO,CAAC,CAAC,2BAAwB,MAAM,IAAI;AAC/F,UAAM,CAAC,MAAM,CAAC,IAAI;AAClB,UAAM,KAAK,IAAI;AACf,QAAI,MAAM,OAAO,SAAS,EAAG;AAC7B,QAAI,EAAE,SAAS,QAAS,UAAS,EAAE,SAAS,CAAC;AAAA,aACpC,EAAE,SAAS,YAAa,UAASD,QAAO,IAAI,EAAE,MAAM,GAAG,UAAU,CAAC;AAAA,QACtE,OAAM,IAAI,MAAM,+CAA+C,MAAM,IAAI;AAAA,EAChF;AACA,SAAO;AACT;AAGA,SAAS,UAAU,IAAY,OAAyC;AACtE,QAAM,MAAM,OAAO,UAAU;AAC7B,UAAQ,IAAI;AAAA,IACV,KAAK;AACH,aAAO,EAAE,OAAO,MAAM,IAAI,KAAK,MAAM,MAAM;AAAA,IAC7C,KAAK;AACH,aAAO,EAAE,OAAO,MAAM,GAAG,KAAK,MAAM,MAAM;AAAA,IAC5C,KAAK;AAAA,IACL,KAAK;AACH,aAAO,EAAE,IAAI,MAAM;AAAA,IACrB,KAAK;AACH,aAAO,EAAE,IAAI,MAAM;AAAA,IACrB,KAAK;AAAA,IACL,KAAK;AAAA,IACL,KAAK;AAAA,IACL,KAAK;AACH,aAAO,EAAE,CAAC,EAAE,GAAG,MAAM;AAAA,IACvB,KAAK;AACH,aAAO,EAAE,IAAI,MAAM;AAAA,IACrB,KAAK;AACH,aAAO,EAAE,IAAI,MAAM;AAAA,IACrB,KAAK;AACH,aAAO,EAAE,IAAI,MAAM;AAAA,IACrB,KAAK;AACH,aAAO,EAAE,OAAO,MAAM;AAAA,IACxB,KAAK;AACH,aAAO,EAAE,IAAI,KAAK;AAAA,IACpB,KAAK;AACH,aAAO,EAAE,IAAI,MAAM;AAAA,IACrB,KAAK;AACH,aAAO,EAAE,QAAQ,KAAK;AAAA,IACxB;AACE,aAAO,EAAE,IAAI,MAAM;AAAA,EACvB;AACF;AAGA,SAAS,WACP,QACAA,SACA,OACA,IACA,OACyB;AACzB,QAAM,MAAM,CAAC,QAAiC,QAAyC;AACrF,UAAM,MAAM,MAAM,GAAG;AACrB,UAAM,IAAI,OAAO,GAAG;AACpB,QAAI,QAAQ,MAAM,SAAS,GAAG;AAC5B,YAAM,KAAK,UAAU,IAAI,KAAK;AAC9B,YAAM,UAAU,GAAG,SAAS,YAAY,EAAE,UAAU;AACpD,aAAO,EAAE,CAAC,GAAG,GAAG,WAAW,OAAO,YAAY,EAAE,MAAM,GAAG,IAAI,GAAG;AAAA,IAClE;AACA,QAAI,OAAgC,CAAC;AACrC,QAAI,SAAS;AACb,QAAI,GAAG,SAAS,SAAS;AACvB,aAAO,EAAE,SAAS,CAAC;AACnB,eAAS,EAAE,UAAU;AAAA,IACvB,WAAW,GAAG,SAAS,aAAa;AAClC,aAAOA,QAAO,IAAI,EAAE,MAAM,GAAG,UAAU,CAAC;AACxC,eAAS,EAAE,gBAAgB;AAAA,IAC7B;AACA,UAAM,QAAQ,IAAI,MAAM,MAAM,CAAC;AAC/B,WAAO,EAAE,CAAC,GAAG,GAAG,SAAS,EAAE,MAAM,MAAM,IAAI,MAAM;AAAA,EACnD;AACA,SAAO,IAAIA,QAAO,IAAI,MAAM,GAAG,UAAU,CAAC,GAAG,CAAC;AAChD;AAGA,SAAS,cAAc,QAAsB,QAAgBA,SAAwD;AACnH,MAAI,SAAS,OAAQ,QAAO,EAAE,KAAK,OAAO,IAAI,IAAI,CAAC,MAAM,cAAc,GAAG,QAAQA,OAAM,CAAC,EAAE;AAC3F,MAAI,QAAQ,OAAQ,QAAO,EAAE,IAAI,OAAO,GAAG,IAAI,CAAC,MAAM,cAAc,GAAG,QAAQA,OAAM,CAAC,EAAE;AACxF,QAAM,QAAQ,cAAc,QAAQA,SAAQ,OAAO,IAAI;AACvD,SAAO,WAAW,QAAQA,SAAQ,OAAO,OAAO,IAAI,OAAO,KAAK;AAClE;AAEA,IAAM,QAAQ;AAGd,SAAS,IAAI,OAAgB,SAAS,GAAW;AAC/C,MAAI,UAAU,KAAM,QAAO;AAC3B,MAAI,OAAO,UAAU,SAAU,QAAO,KAAK,UAAU,KAAK;AAC1D,MAAI,OAAO,UAAU,YAAY,OAAO,UAAU,UAAW,QAAO,OAAO,KAAK;AAChF,MAAI,MAAM,QAAQ,KAAK,EAAG,QAAO,IAAI,MAAM,IAAI,CAAC,MAAM,IAAI,GAAG,MAAM,CAAC,EAAE,KAAK,IAAI,CAAC;AAChF,MAAI,OAAO,UAAU,UAAU;AAC7B,UAAM,UAAU,OAAO,QAAQ,KAAgC;AAC/D,QAAI,QAAQ,WAAW,EAAG,QAAO;AACjC,UAAM,MAAM,KAAK,OAAO,SAAS,CAAC;AAClC,UAAM,QAAQ,KAAK,OAAO,MAAM;AAChC,UAAM,OAAO,QACV,IAAI,CAAC,CAAC,GAAG,CAAC,MAAM,GAAG,GAAG,GAAG,MAAM,KAAK,CAAC,IAAI,IAAI,KAAK,UAAU,CAAC,CAAC,KAAK,IAAI,GAAG,SAAS,CAAC,CAAC,EAAE,EACvF,KAAK,KAAK;AACb,WAAO;AAAA,EAAM,IAAI;AAAA,EAAM,KAAK;AAAA,EAC9B;AACA,SAAO,KAAK,UAAU,KAAK;AAC7B;AAGO,SAAS,cAAc,OAAoBA,SAAuC;AACvF,QAAM,QAAiC,CAAC;AACxC,aAAW,CAAC,QAAQ,IAAI,KAAK,OAAO,QAAQ,MAAM,QAAQ,GAAG;AAC3D,UAAM,MAA+B,EAAE,OAAO,KAAK,MAAM;AACzD,QAAI,KAAK,KAAM,KAAI,OAAO,IAAI,cAAc,KAAK,MAAM,QAAQA,OAAM;AACrE,QAAI,KAAK,QAAQ;AACf,YAAM,QAAQ,KAAK,OAAO,MAAM,IAAI,CAAC,MAAM,cAAc,QAAQA,SAAQ,CAAC,EAAE,KAAK,GAAG,CAAC;AACrF,UAAI,QAAQ,IAAI,KAAK,OAAO,SAAS,YAAY,EAAE,SAAS,MAAM,IAAI,EAAE,SAAS,MAAM;AAAA,IACzF;AACA,UAAM,MAAM,IAAI;AAAA,EAClB;AACA,SAAO;AAAA,IACL;AAAA,IACA;AAAA,IACA,8BAA8B,KAAK,UAAU,MAAM,IAAI,CAAC,KAAK,IAAI,KAAK,CAAC;AAAA,IACvE;AAAA,EACF,EAAE,KAAK,IAAI;AACb;AAKA,SAAS,aAAa,OAAyB;AAC7C,SAAO;AAAA,IACL;AAAA,IACA,GAAG,MAAM,IAAI,CAAC,MAAM,uBAAuB,CAAC,cAAc,CAAC,OAAO;AAAA,IAClE;AAAA,EACF,EAAE,KAAK,IAAI;AACb;AAGA,SAAS,eAAuB;AAC9B,SAAO;AAAA,IACL;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF,EAAE,KAAK,IAAI;AACb;AAiBA,eAAe,UAAa,WAAsB,KAAa,KAAa,MAA0B;AACpG,QAAM,MAAM,MAAM,UAAU,IAAI,QAAQ,KAAK,EAAE,QAAQ,OAAO,SAAS,EAAE,aAAa,IAAI,EAAE,CAAC,CAAC;AAC9F,QAAME,QAAQ,MAAM,IAAI,KAAK,EAAE,MAAM,MAAM,IAAI;AAC/C,MAAI,CAAC,IAAI,MAAM,CAACA,MAAM,OAAM,SAAS,IAAI,QAAQA,OAAM,SAAS,kBAAkB,IAAI,GAAG;AACzF,SAAOA;AACT;AAOA,eAAsB,WAAW,SAA0C;AACzE,QAAM,YAAuB,QAAQ,UAAU,CAAC,QAAQ,WAAW,MAAM,GAAG;AAC5E,QAAM,OAAO,QAAQ,IAAI,QAAQ,OAAO,EAAE;AAE1C,QAAM,OAAO,MAAM,UAAoC,WAAW,GAAG,IAAI,mBAAmB,QAAQ,KAAK,UAAU;AACnH,QAAM,OAAO,MAAM,UAAqC,WAAW,GAAG,IAAI,iBAAiB,QAAQ,KAAK,QAAQ;AAEhH,QAAMF,UAAS,IAAI,IAAI,KAAK,SAAS,IAAI,CAAC,MAAM,CAAC,EAAE,MAAM,CAAC,CAAU,CAAC;AACrE,QAAM,QAAgC,CAAC;AAEvC,QAAM,cAAwB,CAAC;AAC/B,aAAW,MAAM,KAAK,UAAU;AAC9B,UAAM,YAAY,GAAG,IAAI,KAAK,IAAI,WAAW,IAAI,EAAE,QAAQ,KAAK,CAAC;AACjE,gBAAY,KAAK,GAAG,IAAI;AAAA,EAC1B;AACA,cAAY,KAAK;AACjB,QAAM,mBAAmB,IAAI,aAAa,WAAW;AAErD,QAAM,aAAuB,CAAC;AAC9B,aAAW,KAAK,KAAK,QAAQ;AAG3B,QAAI;AACF,YAAM,UAAU,EAAE,IAAI,KAAK,IAAI,cAAc,GAAGA,OAAM;AACtD,iBAAW,KAAK,EAAE,IAAI;AAAA,IACxB,QAAQ;AAAA,IAER;AAAA,EACF;AACA,aAAW,KAAK;AAChB,QAAM,iBAAiB,IAAI,aAAa,UAAU;AAElD,QAAM,UAAU,IAAI,aAAa;AAEjC,SAAO,EAAE,OAAO,UAAU,aAAa,QAAQ,WAAW;AAC5D;AAWA,eAAsB,aAAa,SAAmF;AACpH,QAAM,YAAuB,QAAQ,UAAU,CAAC,QAAQ,WAAW,MAAM,GAAG;AAC5E,QAAM,OAAO,QAAQ,IAAI,QAAQ,OAAO,EAAE;AAC1C,QAAME,QAAO,MAAM,UAAoC,WAAW,GAAG,IAAI,mBAAmB,QAAQ,KAAK,UAAU;AAEnH,QAAM,QAAgC,CAAC;AACvC,QAAM,QAAkB,CAAC;AACzB,aAAW,MAAMA,MAAK,UAAU;AAC9B,UAAM,GAAG,GAAG,IAAI,KAAK,IAAI,WAAW,EAAE;AACtC,UAAM,KAAK,GAAG,IAAI;AAAA,EACpB;AACA,SAAO,EAAE,OAAO,OAAO,MAAM,KAAK,EAAE;AACtC;","names":["int2","int4","int8","numeric","float4","float8","text","varchar","bpchar","timestamptz","timestamp","date","time","interval","bool","uuid","json","jsonb","bytea","byName","json","byName","s","byName","f","json"]}
|
package/dist/cli.d.ts
ADDED
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import { Entity, ShapeRecord } from '@mauroandre/weave-core';
|
|
3
|
+
import { S as ScopeDef, F as FetchLike } from './scope-DrcCzdf-.js';
|
|
4
|
+
|
|
5
|
+
/** Importa um módulo por caminho absoluto. Injetável (a CLI usa um loader de TS). */
|
|
6
|
+
type ModuleLoader = (absPath: string) => Promise<{
|
|
7
|
+
default?: unknown;
|
|
8
|
+
}>;
|
|
9
|
+
/**
|
|
10
|
+
* Lê a pasta de entidades, importa o `default` de cada arquivo, e monta o objeto
|
|
11
|
+
* `entities` chaveado pelo nome da entidade — o mesmo que o `pushEntities`/`createClient`
|
|
12
|
+
* consomem. Ignora arquivos sem `export default defineEntity(...)`.
|
|
13
|
+
*/
|
|
14
|
+
declare function discoverEntities(entitiesDir: string, load?: ModuleLoader): Promise<Record<string, Entity<string, ShapeRecord>>>;
|
|
15
|
+
/**
|
|
16
|
+
* Lê a pasta de scopes (1 arquivo = 1 scope, `export default defineScope(...)`),
|
|
17
|
+
* chaveando pelo nome do scope. Pasta ausente → `{}` (scopes são opcionais). O
|
|
18
|
+
* barrel `index.ts` não tem default export, então é ignorado naturalmente.
|
|
19
|
+
*/
|
|
20
|
+
declare function discoverScopes(scopesDir: string, load?: ModuleLoader): Promise<Record<string, ScopeDef>>;
|
|
21
|
+
|
|
22
|
+
interface ParsedArgs {
|
|
23
|
+
command: string;
|
|
24
|
+
config: string;
|
|
25
|
+
confirm: Record<string, string[]>;
|
|
26
|
+
fill: Record<string, Record<string, unknown>>;
|
|
27
|
+
renames: Record<string, Record<string, string>>;
|
|
28
|
+
/** `--no-gen`: após o push, NÃO re-sincroniza os arquivos locais (CI, read-only). */
|
|
29
|
+
noGen: boolean;
|
|
30
|
+
}
|
|
31
|
+
declare function parseArgs(argv: string[]): ParsedArgs;
|
|
32
|
+
interface CliDeps {
|
|
33
|
+
/** Importador de módulo (config + entidades). Default: dynamic import. */
|
|
34
|
+
load?: ModuleLoader;
|
|
35
|
+
/** Transporte HTTP. Default: globalThis.fetch. */
|
|
36
|
+
fetch?: FetchLike;
|
|
37
|
+
/** Escreve arquivo (pull/gen). Default: fs. */
|
|
38
|
+
write?: (file: string, content: string) => Promise<void>;
|
|
39
|
+
/** Apaga pasta (gen, antes de reescrever). Default: fs.rm. */
|
|
40
|
+
clean?: (dir: string) => Promise<void>;
|
|
41
|
+
/** Variáveis de ambiente (WEAVE_URL/WEAVE_KEY). Default: process.env. */
|
|
42
|
+
env?: Record<string, string | undefined>;
|
|
43
|
+
cwd?: string;
|
|
44
|
+
log?: (msg: string) => void;
|
|
45
|
+
}
|
|
46
|
+
/** Roda o CLI. Devolve o exit code (0 ok; 1 erro / precisa de revisão). */
|
|
47
|
+
declare function runCli(argv: string[], deps?: CliDeps): Promise<number>;
|
|
48
|
+
declare function main(): Promise<void>;
|
|
49
|
+
|
|
50
|
+
export { type CliDeps, type ModuleLoader, type ParsedArgs, discoverEntities, discoverScopes, main, parseArgs, runCli };
|
package/dist/cli.js
ADDED
|
@@ -0,0 +1,169 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import {
|
|
3
|
+
DEFAULT_DIR,
|
|
4
|
+
genProject,
|
|
5
|
+
pullEntities,
|
|
6
|
+
pushEntities,
|
|
7
|
+
pushScopes
|
|
8
|
+
} from "./chunk-PWTED7ZO.js";
|
|
9
|
+
|
|
10
|
+
// src/cli.ts
|
|
11
|
+
import path2 from "path";
|
|
12
|
+
import { pathToFileURL as pathToFileURL2 } from "url";
|
|
13
|
+
|
|
14
|
+
// src/discover.ts
|
|
15
|
+
import fs from "fs/promises";
|
|
16
|
+
import path from "path";
|
|
17
|
+
import { pathToFileURL } from "url";
|
|
18
|
+
var isEntity = (v) => !!v && typeof v === "object" && "name" in v && "columns" in v;
|
|
19
|
+
async function discoverEntities(entitiesDir, load = (p) => import(pathToFileURL(p).href)) {
|
|
20
|
+
const files = (await fs.readdir(entitiesDir)).filter((f) => /\.(ts|tsx|mts|js|mjs)$/.test(f) && !f.endsWith(".d.ts")).sort();
|
|
21
|
+
const entities = {};
|
|
22
|
+
for (const f of files) {
|
|
23
|
+
const mod = await load(path.resolve(entitiesDir, f));
|
|
24
|
+
if (isEntity(mod.default)) entities[mod.default.name] = mod.default;
|
|
25
|
+
}
|
|
26
|
+
return entities;
|
|
27
|
+
}
|
|
28
|
+
var isScope = (v) => !!v && typeof v === "object" && "name" in v && "entities" in v && !("columns" in v);
|
|
29
|
+
async function discoverScopes(scopesDir, load = (p) => import(pathToFileURL(p).href)) {
|
|
30
|
+
let names;
|
|
31
|
+
try {
|
|
32
|
+
names = await fs.readdir(scopesDir);
|
|
33
|
+
} catch {
|
|
34
|
+
return {};
|
|
35
|
+
}
|
|
36
|
+
const files = names.filter((f) => /\.(ts|tsx|mts|js|mjs)$/.test(f) && !f.endsWith(".d.ts")).sort();
|
|
37
|
+
const scopes = {};
|
|
38
|
+
for (const f of files) {
|
|
39
|
+
const mod = await load(path.resolve(scopesDir, f));
|
|
40
|
+
if (isScope(mod.default)) scopes[mod.default.name] = mod.default;
|
|
41
|
+
}
|
|
42
|
+
return scopes;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
// src/cli.ts
|
|
46
|
+
async function defaultWrite(file, content) {
|
|
47
|
+
const fs2 = await import("fs/promises");
|
|
48
|
+
await fs2.mkdir(path2.dirname(file), { recursive: true });
|
|
49
|
+
await fs2.writeFile(file, content, "utf8");
|
|
50
|
+
}
|
|
51
|
+
async function defaultClean(dir) {
|
|
52
|
+
const fs2 = await import("fs/promises");
|
|
53
|
+
await fs2.rm(dir, { recursive: true, force: true });
|
|
54
|
+
}
|
|
55
|
+
function splitEntity(s) {
|
|
56
|
+
if (!s) return ["", ""];
|
|
57
|
+
const i = s.indexOf(".");
|
|
58
|
+
return i < 0 ? [s, ""] : [s.slice(0, i), s.slice(i + 1)];
|
|
59
|
+
}
|
|
60
|
+
function parseArgs(argv) {
|
|
61
|
+
const out = { command: argv[0] ?? "", config: "weave.config.ts", confirm: {}, fill: {}, renames: {}, noGen: false };
|
|
62
|
+
for (let i = 1; i < argv.length; i++) {
|
|
63
|
+
const a = argv[i];
|
|
64
|
+
if (a === "--config") out.config = argv[++i] ?? out.config;
|
|
65
|
+
else if (a === "--no-gen") out.noGen = true;
|
|
66
|
+
else if (a === "--confirm") {
|
|
67
|
+
const [e, p] = splitEntity(argv[++i]);
|
|
68
|
+
if (e && p) (out.confirm[e] ??= []).push(p);
|
|
69
|
+
} else if (a === "--fill") {
|
|
70
|
+
const [ep, v = ""] = (argv[++i] ?? "").split(/=(.*)/s);
|
|
71
|
+
const [e, p] = splitEntity(ep);
|
|
72
|
+
if (e && p) (out.fill[e] ??= {})[p] = v;
|
|
73
|
+
} else if (a === "--rename") {
|
|
74
|
+
const [ep, to = ""] = (argv[++i] ?? "").split(/=(.*)/s);
|
|
75
|
+
const [e, p] = splitEntity(ep);
|
|
76
|
+
if (e && p && to) (out.renames[e] ??= {})[p] = to;
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
return out;
|
|
80
|
+
}
|
|
81
|
+
var riskIcon = (r) => r === "auto" ? "\u{1F7E2}" : r === "confirm" ? "\u{1F534}" : r === "needsValue" ? "\u{1F7E1}" : "\u26D4";
|
|
82
|
+
async function runCli(argv, deps = {}) {
|
|
83
|
+
const args = parseArgs(argv);
|
|
84
|
+
const log = deps.log ?? ((m) => console.log(m));
|
|
85
|
+
const load = deps.load ?? ((p) => import(pathToFileURL2(p).href));
|
|
86
|
+
const cwd = deps.cwd ?? process.cwd();
|
|
87
|
+
const env = deps.env ?? process.env;
|
|
88
|
+
if (!["push", "pull", "gen"].includes(args.command)) {
|
|
89
|
+
log(`Unknown command '${args.command}'. Try: weave push | pull | gen`);
|
|
90
|
+
return 1;
|
|
91
|
+
}
|
|
92
|
+
const url = env["WEAVE_URL"];
|
|
93
|
+
const key = env["WEAVE_KEY"];
|
|
94
|
+
if (!url || !key) {
|
|
95
|
+
log("Set WEAVE_URL and WEAVE_KEY in the environment.");
|
|
96
|
+
return 1;
|
|
97
|
+
}
|
|
98
|
+
const configPath = path2.resolve(cwd, args.config);
|
|
99
|
+
let config = {};
|
|
100
|
+
try {
|
|
101
|
+
config = (await load(configPath)).default ?? {};
|
|
102
|
+
} catch {
|
|
103
|
+
}
|
|
104
|
+
const dirRel = config.dir ?? DEFAULT_DIR;
|
|
105
|
+
const dir = path2.resolve(cwd, dirRel);
|
|
106
|
+
const entitiesDir = path2.join(dir, "entities");
|
|
107
|
+
const net = { url, key, ...deps.fetch ? { fetch: deps.fetch } : {} };
|
|
108
|
+
const write = deps.write ?? defaultWrite;
|
|
109
|
+
const clean = deps.clean ?? defaultClean;
|
|
110
|
+
const regen = async () => {
|
|
111
|
+
const { files, entities: entities2, scopes: scopes2 } = await genProject(net);
|
|
112
|
+
await clean(path2.join(dir, "entities"));
|
|
113
|
+
await clean(path2.join(dir, "scopes"));
|
|
114
|
+
for (const [rel, content] of Object.entries(files)) await write(path2.join(dir, rel), content);
|
|
115
|
+
log(`\u2713 generated ${entities2.length} ${entities2.length === 1 ? "entity" : "entities"}, ${scopes2.length} ${scopes2.length === 1 ? "scope" : "scopes"} \u2192 ${dirRel}/`);
|
|
116
|
+
};
|
|
117
|
+
if (args.command === "gen") {
|
|
118
|
+
await regen();
|
|
119
|
+
return 0;
|
|
120
|
+
}
|
|
121
|
+
if (args.command === "pull") {
|
|
122
|
+
const { files, names } = await pullEntities(net);
|
|
123
|
+
for (const [file, content] of Object.entries(files)) await write(path2.join(entitiesDir, file), content);
|
|
124
|
+
log(`\u2713 pulled ${names.length} ${names.length === 1 ? "entity" : "entities"} \u2192 ${dirRel}/entities`);
|
|
125
|
+
return 0;
|
|
126
|
+
}
|
|
127
|
+
const entities = await discoverEntities(entitiesDir, load);
|
|
128
|
+
if (Object.keys(entities).length === 0) {
|
|
129
|
+
log(`No entities found in ${dirRel}/entities.`);
|
|
130
|
+
return 1;
|
|
131
|
+
}
|
|
132
|
+
const res = await pushEntities(entities, {
|
|
133
|
+
...net,
|
|
134
|
+
confirm: args.confirm,
|
|
135
|
+
fill: args.fill,
|
|
136
|
+
renames: args.renames
|
|
137
|
+
});
|
|
138
|
+
for (const n of res.applied) log(` \u{1F7E2} ${n} applied`);
|
|
139
|
+
for (const r of res.review) {
|
|
140
|
+
log(` \u26A0 ${r.name} \u2014 needs review:`);
|
|
141
|
+
for (const c of r.plan.changes) log(` ${riskIcon(c.risk)} ${c.op} ${c.path} (${c.risk})`);
|
|
142
|
+
}
|
|
143
|
+
if (res.review.length > 0) {
|
|
144
|
+
log("Run again with --confirm / --fill / --rename to apply the gated changes.");
|
|
145
|
+
return 1;
|
|
146
|
+
}
|
|
147
|
+
log(`\u2713 pushed ${res.applied.length} ${res.applied.length === 1 ? "entity" : "entities"}.`);
|
|
148
|
+
const scopes = await discoverScopes(path2.join(dir, "scopes"), load);
|
|
149
|
+
if (Object.keys(scopes).length > 0) {
|
|
150
|
+
const { pushed } = await pushScopes(scopes, net);
|
|
151
|
+
log(`\u2713 pushed ${pushed.length} ${pushed.length === 1 ? "scope" : "scopes"}.`);
|
|
152
|
+
}
|
|
153
|
+
if (!args.noGen) await regen();
|
|
154
|
+
return 0;
|
|
155
|
+
}
|
|
156
|
+
async function main() {
|
|
157
|
+
process.exit(await runCli(process.argv.slice(2)));
|
|
158
|
+
}
|
|
159
|
+
if (process.argv[1] && import.meta.url === pathToFileURL2(process.argv[1]).href) {
|
|
160
|
+
void main();
|
|
161
|
+
}
|
|
162
|
+
export {
|
|
163
|
+
discoverEntities,
|
|
164
|
+
discoverScopes,
|
|
165
|
+
main,
|
|
166
|
+
parseArgs,
|
|
167
|
+
runCli
|
|
168
|
+
};
|
|
169
|
+
//# sourceMappingURL=cli.js.map
|
package/dist/cli.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/cli.ts","../src/discover.ts"],"sourcesContent":["#!/usr/bin/env node\nimport path from \"node:path\";\nimport { pathToFileURL } from \"node:url\";\nimport { discoverEntities, discoverScopes, type ModuleLoader } from \"./discover.js\";\nimport { pushEntities } from \"./push.js\";\nimport { pushScopes } from \"./scope.js\";\nimport { pullEntities, genProject } from \"./gen.js\";\nimport { DEFAULT_DIR, type WeaveConfig } from \"./config.js\";\n\n// Barrel node-only (`@mauroandre/weave-sdk/cli`): a descoberta usa `node:fs`, então\n// fica fora do barrel principal (que é portável p/ browser).\nexport { discoverEntities, discoverScopes, type ModuleLoader } from \"./discover.js\";\n\n/** Escreve um arquivo (criando dirs). Injetável pra teste. */\nasync function defaultWrite(file: string, content: string): Promise<void> {\n const fs = await import(\"node:fs/promises\");\n await fs.mkdir(path.dirname(file), { recursive: true });\n await fs.writeFile(file, content, \"utf8\");\n}\n\n/** Apaga uma pasta recursivamente (idempotente). Injetável pra teste. */\nasync function defaultClean(dir: string): Promise<void> {\n const fs = await import(\"node:fs/promises\");\n await fs.rm(dir, { recursive: true, force: true });\n}\nimport type { FetchLike } from \"./client.js\";\n\n// CLI `weave`. Comandos: `gen` (server → pasta weave/: entidades com $id, scopes,\n// barrels e client — overwrite cego), `push` (código → server, plan/apply em ordem\n// de dep), `pull` (legado: só entidades). url/key vêm do ambiente (WEAVE_URL/\n// WEAVE_KEY); a pasta de destino do `weave.config.ts` (`dir`, default \"weave\").\n// Flags: --config, --confirm, --fill, --rename. Carrega TS via runtime TS-capaz\n// (Node 22.6+ com --experimental-strip-types, ou tsx/jiti).\n\nexport interface ParsedArgs {\n command: string;\n config: string;\n confirm: Record<string, string[]>;\n fill: Record<string, Record<string, unknown>>;\n renames: Record<string, Record<string, string>>;\n /** `--no-gen`: após o push, NÃO re-sincroniza os arquivos locais (CI, read-only). */\n noGen: boolean;\n}\n\n/** \"product.legacy\" → [\"product\", \"legacy\"]; \"product.items.qty\" → [\"product\",\"items.qty\"]. */\nfunction splitEntity(s: string | undefined): [string, string] {\n if (!s) return [\"\", \"\"];\n const i = s.indexOf(\".\");\n return i < 0 ? [s, \"\"] : [s.slice(0, i), s.slice(i + 1)];\n}\n\nexport function parseArgs(argv: string[]): ParsedArgs {\n const out: ParsedArgs = { command: argv[0] ?? \"\", config: \"weave.config.ts\", confirm: {}, fill: {}, renames: {}, noGen: false };\n for (let i = 1; i < argv.length; i++) {\n const a = argv[i];\n if (a === \"--config\") out.config = argv[++i] ?? out.config;\n else if (a === \"--no-gen\") out.noGen = true;\n else if (a === \"--confirm\") {\n const [e, p] = splitEntity(argv[++i]);\n if (e && p) (out.confirm[e] ??= []).push(p);\n } else if (a === \"--fill\") {\n const [ep, v = \"\"] = (argv[++i] ?? \"\").split(/=(.*)/s);\n const [e, p] = splitEntity(ep);\n if (e && p) (out.fill[e] ??= {})[p] = v;\n } else if (a === \"--rename\") {\n const [ep, to = \"\"] = (argv[++i] ?? \"\").split(/=(.*)/s);\n const [e, p] = splitEntity(ep);\n if (e && p && to) (out.renames[e] ??= {})[p] = to;\n }\n }\n return out;\n}\n\nexport interface CliDeps {\n /** Importador de módulo (config + entidades). Default: dynamic import. */\n load?: ModuleLoader;\n /** Transporte HTTP. Default: globalThis.fetch. */\n fetch?: FetchLike;\n /** Escreve arquivo (pull/gen). Default: fs. */\n write?: (file: string, content: string) => Promise<void>;\n /** Apaga pasta (gen, antes de reescrever). Default: fs.rm. */\n clean?: (dir: string) => Promise<void>;\n /** Variáveis de ambiente (WEAVE_URL/WEAVE_KEY). Default: process.env. */\n env?: Record<string, string | undefined>;\n cwd?: string;\n log?: (msg: string) => void;\n}\n\nconst riskIcon = (r: string): string =>\n r === \"auto\" ? \"🟢\" : r === \"confirm\" ? \"🔴\" : r === \"needsValue\" ? \"🟡\" : \"⛔\";\n\n/** Roda o CLI. Devolve o exit code (0 ok; 1 erro / precisa de revisão). */\nexport async function runCli(argv: string[], deps: CliDeps = {}): Promise<number> {\n const args = parseArgs(argv);\n const log = deps.log ?? ((m: string) => console.log(m));\n const load: ModuleLoader = deps.load ?? ((p) => import(pathToFileURL(p).href));\n const cwd = deps.cwd ?? process.cwd();\n const env = deps.env ?? process.env;\n\n if (![\"push\", \"pull\", \"gen\"].includes(args.command)) {\n log(`Unknown command '${args.command}'. Try: weave push | pull | gen`);\n return 1;\n }\n\n const url = env[\"WEAVE_URL\"];\n const key = env[\"WEAVE_KEY\"];\n if (!url || !key) {\n log(\"Set WEAVE_URL and WEAVE_KEY in the environment.\");\n return 1;\n }\n\n // Config é opcional (só `dir`, default \"weave\"); ausente/ilegível → defaults.\n const configPath = path.resolve(cwd, args.config);\n let config: WeaveConfig = {};\n try {\n config = ((await load(configPath)).default ?? {}) as WeaveConfig;\n } catch {\n /* sem weave.config.ts — usa defaults */\n }\n const dirRel = config.dir ?? DEFAULT_DIR;\n const dir = path.resolve(cwd, dirRel);\n const entitiesDir = path.join(dir, \"entities\");\n const net = { url, key, ...(deps.fetch ? { fetch: deps.fetch } : {}) };\n const write = deps.write ?? defaultWrite;\n const clean = deps.clean ?? defaultClean;\n\n // Regenera a pasta weave/ a partir do server (overwrite cego). Usado pelo `gen`\n // e ao fim do `push` (re-sincroniza os $id recém-cunhados), salvo `--no-gen`.\n const regen = async (): Promise<void> => {\n const { files, entities, scopes } = await genProject(net);\n await clean(path.join(dir, \"entities\"));\n await clean(path.join(dir, \"scopes\"));\n for (const [rel, content] of Object.entries(files)) await write(path.join(dir, rel), content);\n log(`✓ generated ${entities.length} ${entities.length === 1 ? \"entity\" : \"entities\"}, ${scopes.length} ${scopes.length === 1 ? \"scope\" : \"scopes\"} → ${dirRel}/`);\n };\n\n // gen: server → pasta weave/ inteira (arquivos com $id, scopes resolvidos, barrels, client).\n if (args.command === \"gen\") {\n await regen();\n return 0;\n }\n\n // pull (legado): puxa os IRs remotos → escreve os arquivos de entidade (sem $id).\n if (args.command === \"pull\") {\n const { files, names } = await pullEntities(net);\n for (const [file, content] of Object.entries(files)) await write(path.join(entitiesDir, file), content);\n log(`✓ pulled ${names.length} ${names.length === 1 ? \"entity\" : \"entities\"} → ${dirRel}/entities`);\n return 0;\n }\n\n // push: tudo vai — entidades primeiro (cunham/fixam ids), depois scopes (resolvem\n // nome→id contra o server), e por fim o gen re-sincroniza os arquivos locais.\n const entities = await discoverEntities(entitiesDir, load);\n if (Object.keys(entities).length === 0) {\n log(`No entities found in ${dirRel}/entities.`);\n return 1;\n }\n\n const res = await pushEntities(entities, {\n ...net,\n confirm: args.confirm,\n fill: args.fill,\n renames: args.renames,\n });\n\n for (const n of res.applied) log(` 🟢 ${n} applied`);\n for (const r of res.review) {\n log(` ⚠ ${r.name} — needs review:`);\n for (const c of r.plan.changes) log(` ${riskIcon(c.risk)} ${c.op} ${c.path} (${c.risk})`);\n }\n // Mudanças bloqueadas no gate → para aqui; scopes/gen ficam pra quando aplicar.\n if (res.review.length > 0) {\n log(\"Run again with --confirm / --fill / --rename to apply the gated changes.\");\n return 1;\n }\n log(`✓ pushed ${res.applied.length} ${res.applied.length === 1 ? \"entity\" : \"entities\"}.`);\n\n // Scopes (só depois das entidades aplicadas — o push resolve nome→id no server).\n const scopes = await discoverScopes(path.join(dir, \"scopes\"), load);\n if (Object.keys(scopes).length > 0) {\n const { pushed } = await pushScopes(scopes, net);\n log(`✓ pushed ${pushed.length} ${pushed.length === 1 ? \"scope\" : \"scopes\"}.`);\n }\n\n // Re-sincroniza os arquivos locais (ids recém-cunhados), salvo --no-gen.\n if (!args.noGen) await regen();\n return 0;\n}\n\nexport async function main(): Promise<void> {\n process.exit(await runCli(process.argv.slice(2)));\n}\n\n// Executado direto (bin) → roda o main.\nif (process.argv[1] && import.meta.url === pathToFileURL(process.argv[1]).href) {\n void main();\n}\n","import fs from \"node:fs/promises\";\nimport path from \"node:path\";\nimport { pathToFileURL } from \"node:url\";\nimport type { Entity, ShapeRecord } from \"@mauroandre/weave-core\";\nimport type { ScopeDef } from \"./scope.js\";\n\n// Descoberta por pasta (file-based, igual o VeloJS acha rotas): cada arquivo é uma\n// entidade, exportada como `default`. Node-only (usa fs) — fora do barrel do SDK.\n\n/** Importa um módulo por caminho absoluto. Injetável (a CLI usa um loader de TS). */\nexport type ModuleLoader = (absPath: string) => Promise<{ default?: unknown }>;\n\nconst isEntity = (v: unknown): v is Entity<string, ShapeRecord> =>\n !!v && typeof v === \"object\" && \"name\" in v && \"columns\" in v;\n\n/**\n * Lê a pasta de entidades, importa o `default` de cada arquivo, e monta o objeto\n * `entities` chaveado pelo nome da entidade — o mesmo que o `pushEntities`/`createClient`\n * consomem. Ignora arquivos sem `export default defineEntity(...)`.\n */\nexport async function discoverEntities(\n entitiesDir: string,\n load: ModuleLoader = (p) => import(pathToFileURL(p).href),\n): Promise<Record<string, Entity<string, ShapeRecord>>> {\n const files = (await fs.readdir(entitiesDir))\n .filter((f) => /\\.(ts|tsx|mts|js|mjs)$/.test(f) && !f.endsWith(\".d.ts\"))\n .sort();\n\n const entities: Record<string, Entity<string, ShapeRecord>> = {};\n for (const f of files) {\n const mod = await load(path.resolve(entitiesDir, f));\n if (isEntity(mod.default)) entities[mod.default.name] = mod.default;\n }\n return entities;\n}\n\nconst isScope = (v: unknown): v is ScopeDef =>\n !!v && typeof v === \"object\" && \"name\" in v && \"entities\" in v && !(\"columns\" in v);\n\n/**\n * Lê a pasta de scopes (1 arquivo = 1 scope, `export default defineScope(...)`),\n * chaveando pelo nome do scope. Pasta ausente → `{}` (scopes são opcionais). O\n * barrel `index.ts` não tem default export, então é ignorado naturalmente.\n */\nexport async function discoverScopes(\n scopesDir: string,\n load: ModuleLoader = (p) => import(pathToFileURL(p).href),\n): Promise<Record<string, ScopeDef>> {\n let names: string[];\n try {\n names = await fs.readdir(scopesDir);\n } catch {\n return {}; // sem pasta de scopes\n }\n const files = names.filter((f) => /\\.(ts|tsx|mts|js|mjs)$/.test(f) && !f.endsWith(\".d.ts\")).sort();\n\n const scopes: Record<string, ScopeDef> = {};\n for (const f of files) {\n const mod = await load(path.resolve(scopesDir, f));\n if (isScope(mod.default)) scopes[mod.default.name] = mod.default;\n }\n return scopes;\n}\n"],"mappings":"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","names":["path","pathToFileURL","fs","path","pathToFileURL","entities","scopes"]}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,148 @@
|
|
|
1
|
+
import { F as FetchLike } from './scope-DrcCzdf-.js';
|
|
2
|
+
export { C as ClientOptions, E as EntityClient, a as FindArgs, P as PageResult, b as PushScopesOptions, S as ScopeDef, c as ScopeEntityRule, V as Verb, W as WeaveClient, d as createClient, e as defineScope, p as pushScopes } from './scope-DrcCzdf-.js';
|
|
3
|
+
import { Entity, ShapeRecord, InferEntity, InferInsert, EntityIR } from '@mauroandre/weave-core';
|
|
4
|
+
export { Entity, InferEntity, InferInsert, InferRead, array, bool, bpchar, bytea, date, defineEntity, float4, float8, int2, int4, int8, interval, json, jsonb, numeric, owned, reference, text, time, timestamp, timestamptz, uuid, varchar } from '@mauroandre/weave-core';
|
|
5
|
+
|
|
6
|
+
/** O objeto como ele VOLTA da leitura (sem expand). `Infer<typeof product>`. */
|
|
7
|
+
type Infer<E extends Entity<string, ShapeRecord>> = InferEntity<E>;
|
|
8
|
+
/** O patch aceito por `update` — `InferInsert` com tudo opcional. */
|
|
9
|
+
type InferUpdate<E extends Entity<string, ShapeRecord>> = Partial<InferInsert<E>>;
|
|
10
|
+
|
|
11
|
+
interface PushOptions {
|
|
12
|
+
/** Base URL do Weave. */
|
|
13
|
+
url: string;
|
|
14
|
+
/** API key (`x-api-key`). */
|
|
15
|
+
key: string;
|
|
16
|
+
/** Transporte. Default: `globalThis.fetch`. Nos testes: `app.hono.fetch`. */
|
|
17
|
+
fetch?: FetchLike;
|
|
18
|
+
/** Caminhos confirmados (drops destrutivos), por nome de entidade. */
|
|
19
|
+
confirm?: Record<string, string[]>;
|
|
20
|
+
/** Valores de backfill (caminho → valor), por nome de entidade. */
|
|
21
|
+
fill?: Record<string, Record<string, unknown>>;
|
|
22
|
+
/**
|
|
23
|
+
* Renames de campo, por entidade: `{ entidade: { nomeAntigo: nomeNovo } }`.
|
|
24
|
+
* Sem isso, renomear no código vira drop+add (com gate); aqui injetamos o id
|
|
25
|
+
* existente no campo novo → o servidor detecta um RENAME (dado preservado).
|
|
26
|
+
*/
|
|
27
|
+
renames?: Record<string, Record<string, string>>;
|
|
28
|
+
}
|
|
29
|
+
/** Uma mudança no plano de migração (em vocabulário de objeto, nunca SQL). */
|
|
30
|
+
interface PlanChange {
|
|
31
|
+
op: string;
|
|
32
|
+
path: string;
|
|
33
|
+
/** `auto` 🟢 · `confirm` 🔴 · `needsValue` 🟡 · `blocked` ⛔ */
|
|
34
|
+
risk: string;
|
|
35
|
+
}
|
|
36
|
+
interface MigrationPlan {
|
|
37
|
+
changes: PlanChange[];
|
|
38
|
+
}
|
|
39
|
+
interface PushResult {
|
|
40
|
+
/** Entidades aplicadas (criadas/migradas). */
|
|
41
|
+
applied: string[];
|
|
42
|
+
/** Entidades que precisam de revisão (com o plano por risco). */
|
|
43
|
+
review: {
|
|
44
|
+
name: string;
|
|
45
|
+
plan: MigrationPlan;
|
|
46
|
+
}[];
|
|
47
|
+
}
|
|
48
|
+
/**
|
|
49
|
+
* Empurra o entities-as-code pro Weave: serializa cada entidade (`toIR`) e aplica via
|
|
50
|
+
* `/admin/entities` (plan/apply seguro). Aplica em **ordem de dependência** (a
|
|
51
|
+
* entidade referida antes da que referencia). Devolve o que foi aplicado e o que
|
|
52
|
+
* precisa de revisão (com o plano por risco) — em vocabulário de objeto, sem SQL.
|
|
53
|
+
*
|
|
54
|
+
* `confirm`/`fill` (por entidade) destravam drops confirmados e backfills.
|
|
55
|
+
*/
|
|
56
|
+
declare function pushEntities(entities: Record<string, Entity<string, ShapeRecord>>, options: PushOptions): Promise<PushResult>;
|
|
57
|
+
|
|
58
|
+
interface WeaveConfig {
|
|
59
|
+
/**
|
|
60
|
+
* Pasta onde o `weave gen` materializa tudo (`entities/`, `scopes/`, `index.ts`).
|
|
61
|
+
* Default: `"weave"` na raiz do projeto. Ex.: `"app/weave"`.
|
|
62
|
+
*/
|
|
63
|
+
dir?: string;
|
|
64
|
+
}
|
|
65
|
+
/** Helper tipado pro `weave.config.ts` (igual `defineConfig` do Vite/Drizzle). */
|
|
66
|
+
declare function defineConfig(config?: WeaveConfig): WeaveConfig;
|
|
67
|
+
|
|
68
|
+
interface IrToSourceOptions {
|
|
69
|
+
/** Emitir `.$id(...)` em cada campo (estável, rename-safe). Default: false. */
|
|
70
|
+
withId?: boolean;
|
|
71
|
+
}
|
|
72
|
+
/** Gera o source `export default defineEntity(...)` de UMA entidade (com imports). */
|
|
73
|
+
declare function irToSource(ir: EntityIR, options?: IrToSourceOptions): string;
|
|
74
|
+
interface StoredCondition {
|
|
75
|
+
path: string[];
|
|
76
|
+
op: string;
|
|
77
|
+
value?: unknown;
|
|
78
|
+
}
|
|
79
|
+
type StoredFilter = StoredCondition | {
|
|
80
|
+
and: StoredFilter[];
|
|
81
|
+
} | {
|
|
82
|
+
or: StoredFilter[];
|
|
83
|
+
};
|
|
84
|
+
interface StoredProjection {
|
|
85
|
+
mode: "include" | "exclude";
|
|
86
|
+
paths: string[][];
|
|
87
|
+
}
|
|
88
|
+
interface StoredRule {
|
|
89
|
+
verbs: string[];
|
|
90
|
+
rows: StoredFilter | null;
|
|
91
|
+
fields: StoredProjection | null;
|
|
92
|
+
}
|
|
93
|
+
interface StoredScope {
|
|
94
|
+
name: string;
|
|
95
|
+
entities: Record<string, StoredRule>;
|
|
96
|
+
}
|
|
97
|
+
/** Gera o source `export default defineScope(...)` de UM scope (resolve id→nome). */
|
|
98
|
+
declare function scopeToSource(scope: StoredScope, byName: Map<string, EntityIR>): string;
|
|
99
|
+
interface GenOptions {
|
|
100
|
+
url: string;
|
|
101
|
+
key: string;
|
|
102
|
+
fetch?: FetchLike;
|
|
103
|
+
}
|
|
104
|
+
interface GenProject {
|
|
105
|
+
/** Caminho relativo (dentro da pasta `weave/`) → conteúdo. */
|
|
106
|
+
files: Record<string, string>;
|
|
107
|
+
entities: string[];
|
|
108
|
+
scopes: string[];
|
|
109
|
+
}
|
|
110
|
+
/**
|
|
111
|
+
* Busca o estado do servidor (entidades + scopes) e gera a árvore de arquivos da
|
|
112
|
+
* pasta `weave/`: `entities/<name>.ts` (com `$id`) + barrel, `scopes/<name>.ts` +
|
|
113
|
+
* barrel, e `index.ts` (client). O CLI limpa a pasta e escreve isto.
|
|
114
|
+
*/
|
|
115
|
+
declare function genProject(options: GenOptions): Promise<GenProject>;
|
|
116
|
+
interface PullOptions {
|
|
117
|
+
url: string;
|
|
118
|
+
key: string;
|
|
119
|
+
fetch?: FetchLike;
|
|
120
|
+
}
|
|
121
|
+
/** Puxa os IRs remotos e gera o source de cada entidade. Devolve `nome.ts → conteúdo`. */
|
|
122
|
+
declare function pullEntities(options: PullOptions): Promise<{
|
|
123
|
+
files: Record<string, string>;
|
|
124
|
+
names: string[];
|
|
125
|
+
}>;
|
|
126
|
+
|
|
127
|
+
declare class WeaveError extends Error {
|
|
128
|
+
readonly status: number;
|
|
129
|
+
constructor(message: string, status: number);
|
|
130
|
+
}
|
|
131
|
+
/** 401 — a API key falta ou é inválida. */
|
|
132
|
+
declare class WeaveAuthError extends WeaveError {
|
|
133
|
+
constructor(message: string);
|
|
134
|
+
}
|
|
135
|
+
/** 403 — o scope nega o verbo/linha/campo. */
|
|
136
|
+
declare class WeaveScopeError extends WeaveError {
|
|
137
|
+
constructor(message: string);
|
|
138
|
+
}
|
|
139
|
+
/** 404 — objeto inexistente (ou fora do alcance do scope). */
|
|
140
|
+
declare class WeaveNotFoundError extends WeaveError {
|
|
141
|
+
constructor(message: string);
|
|
142
|
+
}
|
|
143
|
+
/** 400 — payload inválido (validação de borda). */
|
|
144
|
+
declare class WeaveValidationError extends WeaveError {
|
|
145
|
+
constructor(message: string);
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
export { FetchLike, type GenOptions, type GenProject, type Infer, type InferUpdate, type IrToSourceOptions, type MigrationPlan, type PlanChange, type PullOptions, type PushOptions, type PushResult, WeaveAuthError, type WeaveConfig, WeaveError, WeaveNotFoundError, WeaveScopeError, WeaveValidationError, defineConfig, genProject, irToSource, pullEntities, pushEntities, scopeToSource };
|