Subir archivos a "/"

This commit is contained in:
2025-12-23 16:54:07 +00:00
commit b02694d9ff
222 changed files with 17869 additions and 0 deletions

29
App.svelte Normal file
View File

@@ -0,0 +1,29 @@
<script lang="ts">
import { LoginForm, Dashboard } from './lib/components';
import { authStore } from './lib/stores';
const auth = $derived($authStore);
function handleLoginSuccess() {
console.log('Login exitoso!', auth.user);
}
function handleLogout() {
authStore.logout();
}
</script>
{#if !auth.isAuthenticated}
<!-- Mostrar formulario de login si no está autenticado -->
<div class="min-h-screen bg-gradient-to-br from-blue-50 to-indigo-100 dark:from-gray-900 dark:to-gray-800 py-12 px-4">
<div class="max-w-4xl mx-auto">
<LoginForm onSuccess={handleLoginSuccess} />
</div>
</div>
{:else}
<!-- Mostrar Dashboard cuando está autenticado -->
<Dashboard
username={auth.user?.username || 'Usuario'}
onLogout={handleLogout}
/>
{/if}

136
CHANGELOG.md Normal file
View File

@@ -0,0 +1,136 @@
# Changelog
All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/)
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
## [v1.1.2](https://github.com/ljharb/function-bind/compare/v1.1.1...v1.1.2) - 2023-10-12
### Merged
- Point to the correct file [`#16`](https://github.com/ljharb/function-bind/pull/16)
### Commits
- [Tests] migrate tests to Github Actions [`4f8b57c`](https://github.com/ljharb/function-bind/commit/4f8b57c02f2011fe9ae353d5e74e8745f0988af8)
- [Tests] remove `jscs` [`90eb2ed`](https://github.com/ljharb/function-bind/commit/90eb2edbeefd5b76cd6c3a482ea3454db169b31f)
- [meta] update `.gitignore` [`53fcdc3`](https://github.com/ljharb/function-bind/commit/53fcdc371cd66634d6e9b71c836a50f437e89fed)
- [Tests] up to `node` `v11.10`, `v10.15`, `v9.11`, `v8.15`, `v6.16`, `v4.9`; use `nvm install-latest-npm`; run audit script in tests [`1fe8f6e`](https://github.com/ljharb/function-bind/commit/1fe8f6e9aed0dfa8d8b3cdbd00c7f5ea0cd2b36e)
- [meta] add `auto-changelog` [`1921fcb`](https://github.com/ljharb/function-bind/commit/1921fcb5b416b63ffc4acad051b6aad5722f777d)
- [Robustness] remove runtime dependency on all builtins except `.apply` [`f743e61`](https://github.com/ljharb/function-bind/commit/f743e61aa6bb2360358c04d4884c9db853d118b7)
- Docs: enable badges; update wording [`503cb12`](https://github.com/ljharb/function-bind/commit/503cb12d998b5f91822776c73332c7adcd6355dd)
- [readme] update badges [`290c5db`](https://github.com/ljharb/function-bind/commit/290c5dbbbda7264efaeb886552a374b869a4bb48)
- [Tests] switch to nyc for coverage [`ea360ba`](https://github.com/ljharb/function-bind/commit/ea360ba907fc2601ed18d01a3827fa2d3533cdf8)
- [Dev Deps] update `eslint`, `@ljharb/eslint-config`, `tape` [`cae5e9e`](https://github.com/ljharb/function-bind/commit/cae5e9e07a5578dc6df26c03ee22851ce05b943c)
- [meta] add `funding` field; create FUNDING.yml [`c9f4274`](https://github.com/ljharb/function-bind/commit/c9f4274aa80ea3aae9657a3938fdba41a3b04ca6)
- [Tests] fix eslint errors from #15 [`f69aaa2`](https://github.com/ljharb/function-bind/commit/f69aaa2beb2fdab4415bfb885760a699d0b9c964)
- [actions] fix permissions [`99a0cd9`](https://github.com/ljharb/function-bind/commit/99a0cd9f3b5bac223a0d572f081834cd73314be7)
- [meta] use `npmignore` to autogenerate an npmignore file [`f03b524`](https://github.com/ljharb/function-bind/commit/f03b524ca91f75a109a5d062f029122c86ecd1ae)
- [Dev Deps] update `@ljharb/eslintconfig`, `eslint`, `tape` [`7af9300`](https://github.com/ljharb/function-bind/commit/7af930023ae2ce7645489532821e4fbbcd7a2280)
- [Dev Deps] update `eslint`, `@ljharb/eslint-config`, `covert`, `tape` [`64a9127`](https://github.com/ljharb/function-bind/commit/64a9127ab0bd331b93d6572eaf6e9971967fc08c)
- [Tests] use `aud` instead of `npm audit` [`e75069c`](https://github.com/ljharb/function-bind/commit/e75069c50010a8fcce2a9ce2324934c35fdb4386)
- [Dev Deps] update `@ljharb/eslint-config`, `aud`, `tape` [`d03555c`](https://github.com/ljharb/function-bind/commit/d03555ca59dea3b71ce710045e4303b9e2619e28)
- [meta] add `safe-publish-latest` [`9c8f809`](https://github.com/ljharb/function-bind/commit/9c8f8092aed027d7e80c94f517aa892385b64f09)
- [Dev Deps] update `@ljharb/eslint-config`, `tape` [`baf6893`](https://github.com/ljharb/function-bind/commit/baf6893e27f5b59abe88bc1995e6f6ed1e527397)
- [meta] create SECURITY.md [`4db1779`](https://github.com/ljharb/function-bind/commit/4db17799f1f28ae294cb95e0081ca2b591c3911b)
- [Tests] add `npm run audit` [`c8b38ec`](https://github.com/ljharb/function-bind/commit/c8b38ec40ed3f85dabdee40ed4148f1748375bc2)
- Revert "Point to the correct file" [`05cdf0f`](https://github.com/ljharb/function-bind/commit/05cdf0fa205c6a3c5ba40bbedd1dfa9874f915c9)
## [v1.1.1](https://github.com/ljharb/function-bind/compare/v1.1.0...v1.1.1) - 2017-08-28
### Commits
- [Tests] up to `node` `v8`; newer npm breaks on older node; fix scripts [`817f7d2`](https://github.com/ljharb/function-bind/commit/817f7d28470fdbff8ef608d4d565dd4d1430bc5e)
- [Dev Deps] update `eslint`, `jscs`, `tape`, `@ljharb/eslint-config` [`854288b`](https://github.com/ljharb/function-bind/commit/854288b1b6f5c555f89aceb9eff1152510262084)
- [Dev Deps] update `tape`, `jscs`, `eslint`, `@ljharb/eslint-config` [`83e639f`](https://github.com/ljharb/function-bind/commit/83e639ff74e6cd6921285bccec22c1bcf72311bd)
- Only apps should have lockfiles [`5ed97f5`](https://github.com/ljharb/function-bind/commit/5ed97f51235c17774e0832e122abda0f3229c908)
- Use a SPDX-compliant “license” field. [`5feefea`](https://github.com/ljharb/function-bind/commit/5feefea0dc0193993e83e5df01ded424403a5381)
## [v1.1.0](https://github.com/ljharb/function-bind/compare/v1.0.2...v1.1.0) - 2016-02-14
### Commits
- Update `eslint`, `tape`; use my personal shared `eslint` config [`9c9062a`](https://github.com/ljharb/function-bind/commit/9c9062abbe9dd70b59ea2c3a3c3a81f29b457097)
- Add `npm run eslint` [`dd96c56`](https://github.com/ljharb/function-bind/commit/dd96c56720034a3c1ffee10b8a59a6f7c53e24ad)
- [New] return the native `bind` when available. [`82186e0`](https://github.com/ljharb/function-bind/commit/82186e03d73e580f95ff167e03f3582bed90ed72)
- [Dev Deps] update `tape`, `jscs`, `eslint`, `@ljharb/eslint-config` [`a3dd767`](https://github.com/ljharb/function-bind/commit/a3dd76720c795cb7f4586b0544efabf8aa107b8b)
- Update `eslint` [`3dae2f7`](https://github.com/ljharb/function-bind/commit/3dae2f7423de30a2d20313ddb1edc19660142fe9)
- Update `tape`, `covert`, `jscs` [`a181eee`](https://github.com/ljharb/function-bind/commit/a181eee0cfa24eb229c6e843a971f36e060a2f6a)
- [Tests] up to `node` `v5.6`, `v4.3` [`964929a`](https://github.com/ljharb/function-bind/commit/964929a6a4ddb36fb128de2bcc20af5e4f22e1ed)
- Test up to `io.js` `v2.1` [`2be7310`](https://github.com/ljharb/function-bind/commit/2be7310f2f74886a7124ca925be411117d41d5ea)
- Update `tape`, `jscs`, `eslint`, `@ljharb/eslint-config` [`45f3d68`](https://github.com/ljharb/function-bind/commit/45f3d6865c6ca93726abcef54febe009087af101)
- [Dev Deps] update `tape`, `jscs` [`6e1340d`](https://github.com/ljharb/function-bind/commit/6e1340d94642deaecad3e717825db641af4f8b1f)
- [Tests] up to `io.js` `v3.3`, `node` `v4.1` [`d9bad2b`](https://github.com/ljharb/function-bind/commit/d9bad2b778b1b3a6dd2876087b88b3acf319f8cc)
- Update `eslint` [`935590c`](https://github.com/ljharb/function-bind/commit/935590caa024ab356102e4858e8fc315b2ccc446)
- [Dev Deps] update `jscs`, `eslint`, `@ljharb/eslint-config` [`8c9a1ef`](https://github.com/ljharb/function-bind/commit/8c9a1efd848e5167887aa8501857a0940a480c57)
- Test on `io.js` `v2.2` [`9a3a38c`](https://github.com/ljharb/function-bind/commit/9a3a38c92013aed6e108666e7bd40969b84ac86e)
- Run `travis-ci` tests on `iojs` and `node` v0.12; speed up builds; allow 0.8 failures. [`69afc26`](https://github.com/ljharb/function-bind/commit/69afc2617405b147dd2a8d8ae73ca9e9283f18b4)
- [Dev Deps] Update `tape`, `eslint` [`36c1be0`](https://github.com/ljharb/function-bind/commit/36c1be0ab12b45fe5df6b0fdb01a5d5137fd0115)
- Update `tape`, `jscs` [`98d8303`](https://github.com/ljharb/function-bind/commit/98d8303cd5ca1c6b8f985469f86b0d44d7d45f6e)
- Update `jscs` [`9633a4e`](https://github.com/ljharb/function-bind/commit/9633a4e9fbf82051c240855166e468ba8ba0846f)
- Update `tape`, `jscs` [`c80ef0f`](https://github.com/ljharb/function-bind/commit/c80ef0f46efc9791e76fa50de4414092ac147831)
- Test up to `io.js` `v3.0` [`7e2c853`](https://github.com/ljharb/function-bind/commit/7e2c8537d52ab9cf5a655755561d8917684c0df4)
- Test on `io.js` `v2.4` [`5a199a2`](https://github.com/ljharb/function-bind/commit/5a199a27ba46795ba5eaf0845d07d4b8232895c9)
- Test on `io.js` `v2.3` [`a511b88`](https://github.com/ljharb/function-bind/commit/a511b8896de0bddf3b56862daa416c701f4d0453)
- Fixing a typo from 822b4e1938db02dc9584aa434fd3a45cb20caf43 [`732d6b6`](https://github.com/ljharb/function-bind/commit/732d6b63a9b33b45230e630dbcac7a10855d3266)
- Update `jscs` [`da52a48`](https://github.com/ljharb/function-bind/commit/da52a4886c06d6490f46ae30b15e4163ba08905d)
- Lock covert to v1.0.0. [`d6150fd`](https://github.com/ljharb/function-bind/commit/d6150fda1e6f486718ebdeff823333d9e48e7430)
## [v1.0.2](https://github.com/ljharb/function-bind/compare/v1.0.1...v1.0.2) - 2014-10-04
## [v1.0.1](https://github.com/ljharb/function-bind/compare/v1.0.0...v1.0.1) - 2014-10-03
### Merged
- make CI build faster [`#3`](https://github.com/ljharb/function-bind/pull/3)
### Commits
- Using my standard jscs.json [`d8ee94c`](https://github.com/ljharb/function-bind/commit/d8ee94c993eff0a84cf5744fe6a29627f5cffa1a)
- Adding `npm run lint` [`7571ab7`](https://github.com/ljharb/function-bind/commit/7571ab7dfdbd99b25a1dbb2d232622bd6f4f9c10)
- Using consistent indentation [`e91a1b1`](https://github.com/ljharb/function-bind/commit/e91a1b13a61e99ec1e530e299b55508f74218a95)
- Updating jscs [`7e17892`](https://github.com/ljharb/function-bind/commit/7e1789284bc629bc9c1547a61c9b227bbd8c7a65)
- Using consistent quotes [`c50b57f`](https://github.com/ljharb/function-bind/commit/c50b57fcd1c5ec38320979c837006069ebe02b77)
- Adding keywords [`cb94631`](https://github.com/ljharb/function-bind/commit/cb946314eed35f21186a25fb42fc118772f9ee00)
- Directly export a function expression instead of using a declaration, and relying on hoisting. [`5a33c5f`](https://github.com/ljharb/function-bind/commit/5a33c5f45642de180e0d207110bf7d1843ceb87c)
- Naming npm URL and badge in README; use SVG [`2aef8fc`](https://github.com/ljharb/function-bind/commit/2aef8fcb79d54e63a58ae557c4e60949e05d5e16)
- Naming deps URLs in README [`04228d7`](https://github.com/ljharb/function-bind/commit/04228d766670ee45ca24e98345c1f6a7621065b5)
- Naming travis-ci URLs in README; using SVG [`62c810c`](https://github.com/ljharb/function-bind/commit/62c810c2f54ced956cd4d4ab7b793055addfe36e)
- Make sure functions are invoked correctly (also passing coverage tests) [`2b289b4`](https://github.com/ljharb/function-bind/commit/2b289b4dfbf037ffcfa4dc95eb540f6165e9e43a)
- Removing the strict mode pragmas; they make tests fail. [`1aa701d`](https://github.com/ljharb/function-bind/commit/1aa701d199ddc3782476e8f7eef82679be97b845)
- Adding myself as a contributor [`85fd57b`](https://github.com/ljharb/function-bind/commit/85fd57b0860e5a7af42de9a287f3f265fc6d72fc)
- Adding strict mode pragmas [`915b08e`](https://github.com/ljharb/function-bind/commit/915b08e084c86a722eafe7245e21db74aa21ca4c)
- Adding devDeps URLs to README [`4ccc731`](https://github.com/ljharb/function-bind/commit/4ccc73112c1769859e4ca3076caf4086b3cba2cd)
- Fixing the description. [`a7a472c`](https://github.com/ljharb/function-bind/commit/a7a472cf649af515c635cf560fc478fbe48999c8)
- Using a function expression instead of a function declaration. [`b5d3e4e`](https://github.com/ljharb/function-bind/commit/b5d3e4ea6aaffc63888953eeb1fbc7ff45f1fa14)
- Updating tape [`f086be6`](https://github.com/ljharb/function-bind/commit/f086be6029fb56dde61a258c1340600fa174d1e0)
- Updating jscs [`5f9bdb3`](https://github.com/ljharb/function-bind/commit/5f9bdb375ab13ba48f30852aab94029520c54d71)
- Updating jscs [`9b409ba`](https://github.com/ljharb/function-bind/commit/9b409ba6118e23395a4e5d83ef39152aab9d3bfc)
- Run coverage as part of tests. [`8e1b6d4`](https://github.com/ljharb/function-bind/commit/8e1b6d459f047d1bd4fee814e01247c984c80bd0)
- Run linter as part of tests [`c1ca83f`](https://github.com/ljharb/function-bind/commit/c1ca83f832df94587d09e621beba682fabfaa987)
- Updating covert [`701e837`](https://github.com/ljharb/function-bind/commit/701e83774b57b4d3ef631e1948143f43a72f4bb9)
## [v1.0.0](https://github.com/ljharb/function-bind/compare/v0.2.0...v1.0.0) - 2014-08-09
### Commits
- Make sure old and unstable nodes don't fail Travis [`27adca3`](https://github.com/ljharb/function-bind/commit/27adca34a4ab6ad67b6dfde43942a1b103ce4d75)
- Fixing an issue when the bound function is called as a constructor in ES3. [`e20122d`](https://github.com/ljharb/function-bind/commit/e20122d267d92ce553859b280cbbea5d27c07731)
- Adding `npm run coverage` [`a2e29c4`](https://github.com/ljharb/function-bind/commit/a2e29c4ecaef9e2f6cd1603e868c139073375502)
- Updating tape [`b741168`](https://github.com/ljharb/function-bind/commit/b741168b12b235b1717ff696087645526b69213c)
- Upgrading tape [`63631a0`](https://github.com/ljharb/function-bind/commit/63631a04c7fbe97cc2fa61829cc27246d6986f74)
- Updating tape [`363cb46`](https://github.com/ljharb/function-bind/commit/363cb46dafb23cb3e347729a22f9448051d78464)
## v0.2.0 - 2014-03-23
### Commits
- Updating test coverage to match es5-shim. [`aa94d44`](https://github.com/ljharb/function-bind/commit/aa94d44b8f9d7f69f10e060db7709aa7a694e5d4)
- initial [`942ee07`](https://github.com/ljharb/function-bind/commit/942ee07e94e542d91798137bc4b80b926137e066)
- Setting the bound function's length properly. [`079f46a`](https://github.com/ljharb/function-bind/commit/079f46a2d3515b7c0b308c2c13fceb641f97ca25)
- Ensuring that some older browsers will throw when given a regex. [`36ac55b`](https://github.com/ljharb/function-bind/commit/36ac55b87f460d4330253c92870aa26fbfe8227f)
- Removing npm scripts that don't have dependencies [`9d2be60`](https://github.com/ljharb/function-bind/commit/9d2be600002cb8bc8606f8f3585ad3e05868c750)
- Updating tape [`297a4ac`](https://github.com/ljharb/function-bind/commit/297a4acc5464db381940aafb194d1c88f4e678f3)
- Skipping length tests for now. [`d9891ea`](https://github.com/ljharb/function-bind/commit/d9891ea4d2aaffa69f408339cdd61ff740f70565)
- don't take my tea [`dccd930`](https://github.com/ljharb/function-bind/commit/dccd930bfd60ea10cb178d28c97550c3bc8c1e07)

29
Dockerfile Normal file
View File

@@ -0,0 +1,29 @@
FROM python:3.11-slim
WORKDIR /code
# Instalar dependencias del sistema
RUN apt-get update && apt-get install -y \
gcc \
postgresql-client \
&& rm -rf /var/lib/apt/lists/*
# Copiar requirements
COPY requirements.txt .
# Instalar dependencias de Python
RUN pip install --no-cache-dir -r requirements.txt
# Copiar el código de la aplicación
COPY ./app /code/app
COPY ./alembic /code/alembic
COPY ./alembic.ini /code/alembic.ini
COPY ./migrate.sh /code/migrate.sh
RUN sed -i 's/\r$//' /code/migrate.sh && chmod +x /code/migrate.sh
# Exponer el puerto
EXPOSE 8009
# Comando para ejecutar la aplicación
CMD ["uvicorn", "app.main:app", "--host", "0.0.0.0", "--port", "8009", "--reload"]

8
Dockerfile.dev Normal file
View File

@@ -0,0 +1,8 @@
FROM node:20-alpine
WORKDIR /app
COPY package*.json ./
RUN npm install
CMD ["npm", "run", "dev", "--", "--host"]

29
Dockerfile.prod Normal file
View File

@@ -0,0 +1,29 @@
# Etapa de construcción
FROM node:20-alpine AS builder
WORKDIR /app
# Copiar archivos de dependencias
COPY package*.json ./
RUN apk update && apk add --no-cache ca-certificates wget && update-ca-certificates
RUN npm config set strict-ssl false
# Instalar todas las dependencias para construcción
RUN npm ci
# Copiar el resto del código
COPY . .
# Crear archivo .env
RUN echo "VITE_API_BASE_URL=http://localhost:8009" > .env
# Construir la aplicación
RUN npm run build
# Etapa de producción
FROM nginx:alpine AS production
COPY --from=builder /app/dist /usr/share/nginx/html
COPY nginx.conf /etc/nginx/conf.d/default.conf
EXPOSE 80
CMD ["nginx", "-g", "daemon off;"]

1
HEAD Normal file
View File

@@ -0,0 +1 @@
ref: refs/heads/main

66
HISTORY.md Normal file
View File

@@ -0,0 +1,66 @@
2.7.0 / 2017-09-13
==================
* feat: support fs.copyFile (#58)
2.6.0 / 2016-11-22
==================
* Added fdatasync to fs api (#46)
2.5.0 / 2016-11-04
==================
* feat: support fs.mkdtemp
2.4.0 / 2016-03-23
==================
* add `fs.truncate()` [#34](https://github.com/normalize/mz/pull/34)
2.3.1 / 2016-02-01
==================
* update `any-promise@v1`
2.3.0 / 2016-01-30
==================
* feat(package): switch to `any-promise` to support more promise engines
2.2.0 / 2016-01-24
==================
* feat(package): add index.js to files
2.1.0 / 2015-10-15
==================
* support for readline library
2.0.0 / 2015-05-24
==================
* support callbacks as well
1.2.0 / 2014-12-16
==================
* refactor promisification to `thenify` and `thenify-all`
1.1.0 / 2014-11-14
==================
* use `graceful-fs` if available
1.0.1 / 2014-08-18
==================
* don't use `bluebird.promisify()` - unnecessarily wraps runtime errors, causing issues
1.0.0 / 2014-06-18
==================
* use `bluebird` by default if found
* support node 0.8

21
LICENSE Normal file
View File

@@ -0,0 +1,21 @@
The MIT License (MIT)
Copyright (c) 2014-2016, Jon Schlinkert
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.

20
LICENSE-MIT.txt Normal file
View File

@@ -0,0 +1,20 @@
Copyright Mathias Bynens <https://mathiasbynens.be/>
Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
"Software"), to deal in the Software without restriction, including
without limitation the rights to use, copy, modify, merge, publish,
distribute, sublicense, and/or sell copies of the Software, and to
permit persons to whom the Software is furnished to do so, subject to
the following conditions:
The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

21
LICENSE.md Normal file
View File

@@ -0,0 +1,21 @@
The MIT License (MIT)
Copyright (c) 2021 Vercel, Inc.
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

201
LICENSE.txt Normal file
View File

@@ -0,0 +1,201 @@
Apache License
Version 2.0, January 2004
http://www.apache.org/licenses/
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
1. Definitions.
"License" shall mean the terms and conditions for use, reproduction,
and distribution as defined by Sections 1 through 9 of this document.
"Licensor" shall mean the copyright owner or entity authorized by
the copyright owner that is granting the License.
"Legal Entity" shall mean the union of the acting entity and all
other entities that control, are controlled by, or are under common
control with that entity. For the purposes of this definition,
"control" means (i) the power, direct or indirect, to cause the
direction or management of such entity, whether by contract or
otherwise, or (ii) ownership of fifty percent (50%) or more of the
outstanding shares, or (iii) beneficial ownership of such entity.
"You" (or "Your") shall mean an individual or Legal Entity
exercising permissions granted by this License.
"Source" form shall mean the preferred form for making modifications,
including but not limited to software source code, documentation
source, and configuration files.
"Object" form shall mean any form resulting from mechanical
transformation or translation of a Source form, including but
not limited to compiled object code, generated documentation,
and conversions to other media types.
"Work" shall mean the work of authorship, whether in Source or
Object form, made available under the License, as indicated by a
copyright notice that is included in or attached to the work
(an example is provided in the Appendix below).
"Derivative Works" shall mean any work, whether in Source or Object
form, that is based on (or derived from) the Work and for which the
editorial revisions, annotations, elaborations, or other modifications
represent, as a whole, an original work of authorship. For the purposes
of this License, Derivative Works shall not include works that remain
separable from, or merely link (or bind by name) to the interfaces of,
the Work and Derivative Works thereof.
"Contribution" shall mean any work of authorship, including
the original version of the Work and any modifications or additions
to that Work or Derivative Works thereof, that is intentionally
submitted to Licensor for inclusion in the Work by the copyright owner
or by an individual or Legal Entity authorized to submit on behalf of
the copyright owner. For the purposes of this definition, "submitted"
means any form of electronic, verbal, or written communication sent
to the Licensor or its representatives, including but not limited to
communication on electronic mailing lists, source code control systems,
and issue tracking systems that are managed by, or on behalf of, the
Licensor for the purpose of discussing and improving the Work, but
excluding communication that is conspicuously marked or otherwise
designated in writing by the copyright owner as "Not a Contribution."
"Contributor" shall mean Licensor and any individual or Legal Entity
on behalf of whom a Contribution has been received by Licensor and
subsequently incorporated within the Work.
2. Grant of Copyright License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
copyright license to reproduce, prepare Derivative Works of,
publicly display, publicly perform, sublicense, and distribute the
Work and such Derivative Works in Source or Object form.
3. Grant of Patent License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
(except as stated in this section) patent license to make, have made,
use, offer to sell, sell, import, and otherwise transfer the Work,
where such license applies only to those patent claims licensable
by such Contributor that are necessarily infringed by their
Contribution(s) alone or by combination of their Contribution(s)
with the Work to which such Contribution(s) was submitted. If You
institute patent litigation against any entity (including a
cross-claim or counterclaim in a lawsuit) alleging that the Work
or a Contribution incorporated within the Work constitutes direct
or contributory patent infringement, then any patent licenses
granted to You under this License for that Work shall terminate
as of the date such litigation is filed.
4. Redistribution. You may reproduce and distribute copies of the
Work or Derivative Works thereof in any medium, with or without
modifications, and in Source or Object form, provided that You
meet the following conditions:
(a) You must give any other recipients of the Work or
Derivative Works a copy of this License; and
(b) You must cause any modified files to carry prominent notices
stating that You changed the files; and
(c) You must retain, in the Source form of any Derivative Works
that You distribute, all copyright, patent, trademark, and
attribution notices from the Source form of the Work,
excluding those notices that do not pertain to any part of
the Derivative Works; and
(d) If the Work includes a "NOTICE" text file as part of its
distribution, then any Derivative Works that You distribute must
include a readable copy of the attribution notices contained
within such NOTICE file, excluding those notices that do not
pertain to any part of the Derivative Works, in at least one
of the following places: within a NOTICE text file distributed
as part of the Derivative Works; within the Source form or
documentation, if provided along with the Derivative Works; or,
within a display generated by the Derivative Works, if and
wherever such third-party notices normally appear. The contents
of the NOTICE file are for informational purposes only and
do not modify the License. You may add Your own attribution
notices within Derivative Works that You distribute, alongside
or as an addendum to the NOTICE text from the Work, provided
that such additional attribution notices cannot be construed
as modifying the License.
You may add Your own copyright statement to Your modifications and
may provide additional or different license terms and conditions
for use, reproduction, or distribution of Your modifications, or
for any such Derivative Works as a whole, provided Your use,
reproduction, and distribution of the Work otherwise complies with
the conditions stated in this License.
5. Submission of Contributions. Unless You explicitly state otherwise,
any Contribution intentionally submitted for inclusion in the Work
by You to the Licensor shall be under the terms and conditions of
this License, without any additional terms or conditions.
Notwithstanding the above, nothing herein shall supersede or modify
the terms of any separate license agreement you may have executed
with Licensor regarding such Contributions.
6. Trademarks. This License does not grant permission to use the trade
names, trademarks, service marks, or product names of the Licensor,
except as required for reasonable and customary use in describing the
origin of the Work and reproducing the content of the NOTICE file.
7. Disclaimer of Warranty. Unless required by applicable law or
agreed to in writing, Licensor provides the Work (and each
Contributor provides its Contributions) on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
implied, including, without limitation, any warranties or conditions
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
PARTICULAR PURPOSE. You are solely responsible for determining the
appropriateness of using or redistributing the Work and assume any
risks associated with Your exercise of permissions under this License.
8. Limitation of Liability. In no event and under no legal theory,
whether in tort (including negligence), contract, or otherwise,
unless required by applicable law (such as deliberate and grossly
negligent acts) or agreed to in writing, shall any Contributor be
liable to You for damages, including any direct, indirect, special,
incidental, or consequential damages of any character arising as a
result of this License or out of the use or inability to use the
Work (including but not limited to damages for loss of goodwill,
work stoppage, computer failure or malfunction, or any and all
other commercial damages or losses), even if such Contributor
has been advised of the possibility of such damages.
9. Accepting Warranty or Additional Liability. While redistributing
the Work or Derivative Works thereof, You may choose to offer,
and charge a fee for, acceptance of support, warranty, indemnity,
or other liability obligations and/or rights consistent with this
License. However, in accepting such obligations, You may act only
on Your own behalf and on Your sole responsibility, not on behalf
of any other Contributor, and only if You agree to indemnify,
defend, and hold each Contributor harmless for any liability
incurred by, or claims asserted against, such Contributor by reason
of your accepting any such warranty or additional liability.
END OF TERMS AND CONDITIONS
APPENDIX: How to apply the Apache License to your work.
To apply the Apache License to your work, attach the following
boilerplate notice, with the fields enclosed by brackets "[]"
replaced with your own identifying information. (Don't include
the brackets!) The text should be enclosed in the appropriate
comment syntax for the file format. We also recommend that a
file or class name and description of purpose be included on the
same "printed page" as the copyright notice for easier
identification within third-party archives.
Copyright [yyyy] [name of copyright owner]
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.

175
MIGRATIONS.md Normal file
View File

@@ -0,0 +1,175 @@
# Guía de Migraciones con Alembic
Este proyecto usa Alembic para manejar las migraciones de base de datos.
## 📋 Comandos Útiles
### Dentro del contenedor Docker
```bash
# Acceder al contenedor
docker exec -it control_mve_api bash
# Crear una nueva migración automáticamente
alembic revision --autogenerate -m "descripción del cambio"
# Aplicar migraciones pendientes
alembic upgrade head
# Revertir última migración
alembic downgrade -1
# Ver historial de migraciones
alembic history
# Ver estado actual
alembic current
```
### Desde el host (sin entrar al contenedor)
```bash
# Crear nueva migración
docker exec -it control_mve_api alembic revision --autogenerate -m "descripción"
# Aplicar migraciones
docker exec -it control_mve_api alembic upgrade head
# Ver historial
docker exec -it control_mve_api alembic history
```
## 🚀 Flujo de Trabajo
### 1. Modificar modelos
Edita tus modelos en `app/models/`:
```python
# Ejemplo: agregar un nuevo campo
class Cliente(Base):
__tablename__ = "clientes"
# ... campos existentes ...
nuevo_campo = Column(String(100))
```
### 2. Generar migración automática
```bash
docker exec -it control_mve_api alembic revision --autogenerate -m "agregar campo nuevo_campo a clientes"
```
Esto creará un archivo en `alembic/versions/` con los cambios detectados.
### 3. Revisar la migración generada
**IMPORTANTE**: Siempre revisa el archivo generado antes de aplicarlo.
```bash
# Ver el archivo más reciente
ls -lt alembic/versions/ | head -n 2
```
### 4. Aplicar la migración
```bash
docker exec -it control_mve_api alembic upgrade head
```
### 5. Verificar que se aplicó
```bash
docker exec -it control_mve_api alembic current
```
## 🔄 Migración Inicial
La migración inicial ya se ejecuta automáticamente cuando levantas los contenedores gracias al script `migrate.sh`.
Si necesitas recrear la migración inicial:
```bash
# Eliminar migraciones existentes
rm alembic/versions/*.py
# Crear migración inicial
docker exec -it control_mve_api alembic revision --autogenerate -m "migración inicial"
# Aplicarla
docker exec -it control_mve_api alembic upgrade head
```
## 📝 Ejemplos Comunes
### Agregar un nuevo modelo
1. Crear archivo en `app/models/nueva_entidad.py`
2. Importarlo en `app/models/__init__.py`
3. Generar migración: `alembic revision --autogenerate -m "agregar modelo NuevaEntidad"`
4. Revisar y aplicar: `alembic upgrade head`
### Modificar un campo existente
1. Editar el modelo
2. Generar migración: `alembic revision --autogenerate -m "modificar campo X"`
3. **Revisar migración** - Alembic no siempre detecta todos los cambios
4. Aplicar: `alembic upgrade head`
### Crear migración manual
Si necesitas hacer cambios que Alembic no detecta automáticamente:
```bash
docker exec -it control_timbres_api alembic revision -m "mi cambio manual"
```
Luego edita el archivo generado en `alembic/versions/`:
```python
def upgrade() -> None:
op.execute("UPDATE clientes SET estado = 'activo' WHERE estado IS NULL")
def downgrade() -> None:
pass
```
## ⚠️ Buenas Prácticas
1. **Siempre revisa** las migraciones autogeneradas antes de aplicarlas
2. **Prueba en desarrollo** antes de aplicar en producción
3. **Haz backup** de la base de datos antes de migraciones importantes
4. **Escribe downgrades** funcionales para poder revertir cambios
5. **Commits pequeños** - una migración por cambio lógico
6. **Nombres descriptivos** para las migraciones
## 🔧 Troubleshooting
### La migración no detecta mis cambios
- Verifica que importaste el modelo en `app/models/__init__.py`
- Asegúrate de que `alembic/env.py` importa todos los modelos
- Reinicia el contenedor: `docker-compose restart api`
### Error: "Target database is not up to date"
```bash
# Ver qué migraciones faltan
docker exec -it control_mve_api alembic current
docker exec -it control_mve_api alembic history
# Aplicar pendientes
docker exec -it control_mve_api alembic upgrade head
```
### Quiero empezar de cero
```bash
# CUIDADO: Esto borra todos los datos
docker-compose down -v
docker-compose up -d
```
## 📚 Recursos
- [Documentación oficial de Alembic](https://alembic.sqlalchemy.org/)
- [Tutorial de Alembic](https://alembic.sqlalchemy.org/en/latest/tutorial.html)

195
README.md Normal file
View File

@@ -0,0 +1,195 @@
# ARIA Query
![CI](https://github.com/A11yance/aria-query/workflows/CI/badge.svg)
Programmatic access to the [WAI-ARIA 1.2 Roles Model](https://www.w3.org/TR/wai-aria-1.2/#roles).
This package tracks the W3C Recommendation (last update: 6 June 2023).
CDN URL: <https://unpkg.com/aria-query>
## Building the `src/etc` files
The files under `src/etc` are generated by the `breakUpAriaJSON` script.
To change them, edit the file `scripts/roles.json` then run:
```bash
node ./scripts/breakUpAriaJSON.js
git add scripts/roles.json src/etc
```
It should work with Node version 6.11.2 or later.
## Utilities
### Interface
These methods are available on each export from the module. The typing here in the documentation is pseudo-typed. Each export will have its own specific types for each method signature.
```javascript
{|
entries: () => Array<$Item>,
get: (key: $Key) => ?$Value,
has: (key: $Key) => boolean,
keys: () => Array<$Key>,
values: () => Array<$Value>,
|};
```
### Roles
```javascript
import { roles } from 'aria-query';
```
A map of role names to the role definition. For example:
```javascript
let alertRole = roles.get('alert');
/**
* Value of alertRole
* {
* "requiredProps": {},
* "props": {
* "aria-atomic": "true",
* "aria-busy": null,
* "aria-controls": null,
* "aria-current": null,
* "aria-describedby": null,
* "aria-details": null,
* "aria-disabled": null,
* "aria-dropeffect": null,
* "aria-errormessage": null,
* "aria-expanded": null,
* "aria-flowto": null,
* "aria-grabbed": null,
* "aria-haspopup": null,
* "aria-hidden": null,
* "aria-invalid": null,
* "aria-keyshortcuts": null,
* "aria-label": null,
* "aria-labelledby": null,
* "aria-live": "assertive",
* "aria-owns": null,
* "aria-relevant": null,
* "aria-roledescription": null
* },
* "abstract": false,
* "childrenPresentational": false,
* "baseConcepts": [],
* "relatedConcepts": [ {
* "module": "XForms",
* "concept": {
* "name": "alert"
* }
* }],
* "superClass": [["roletype", "structure", "section"]]
* }
```
### Elements to Roles
```javascript
import { elementRoles } from 'aria-query';
```
HTML Elements with inherent roles are mapped to those roles. In the case of an element like `<input>`, the element often requires a `type` attribute to map to an ARIA role.
```javascript
[
[ '{"name": "article"}', [ 'article' ] ],
[ '{"name": "button"}', [ 'button' ] ],
[ '{"name": "td"}', [ 'cell', 'gridcell' ] ],
[ '{"name": "input", "attributes": [ {"name": "type", "value": "checkbox"}] }', [ 'checkbox' ] ],
[ '{"name": "th"}', [ 'columnheader' ] ],
[ '{"name": "select"}', [ 'combobox', 'listbox' ] ],
[ '{"name": "menuitem"}', [ 'command', 'menuitem' ] ],
[ '{"name": "dd"}', [ 'definition' ] ],
[ '{"name": "figure"}', [ 'figure' ] ],
[ '{"name": "form"}', [ 'form' ] ],
[ '{"name": "table"}', [ 'grid', 'table' ] ],
[ '{"name": "fieldset"}', [ 'group' ] ],
[ '{"name": "h1"}', [ 'heading' ] ],
[ '{"name": "h2"}', [ 'heading' ] ],
[ '{"name": "h3"}', [ 'heading' ] ],
[ '{"name": "h4"}', [ 'heading' ] ],
[ '{"name": "h5"}', [ 'heading' ] ],
[ '{"name": "h6"}', [ 'heading' ] ],
[ '{"name": "img"}', [ 'img' ] ],
[ '{"name": "a"}', [ 'link' ] ],
[ '{"name": "link"}', [ 'link' ] ],
[ '{"name": "ol"}', [ 'list' ] ],
[ '{"name": "ul"}', [ 'list' ] ],
[ '{"name": "li"}', [ 'listitem' ] ],
[ '{"name": "nav"}', [ 'navigation' ] ],
[ '{"name": "option"}', [ 'option' ] ],
[ '{"name": "input", "attributes": [ {"name": "type", "value": "radio"}] }', [ 'radio' ] ],
[ '{"name": "frame"}', [ 'region' ] ],
[ '{"name": "rel"}', [ 'roletype' ] ],
[ '{"name": "tr"}', [ 'row' ] ],
[ '{"name": "tbody"}', [ 'rowgroup' ] ],
[ '{"name": "tfoot"}', [ 'rowgroup' ] ],
[ '{"name": "thead"}', [ 'rowgroup' ] ],
[ '{"name": "th", "attributes": [ {"name": "scope", "value": "row"}] }', [ 'rowheader' ] ],
[ '{"name": "input", "attributes": [ {"name": "type", "value": "search"}] }', [ 'searchbox' ] ],
[ '{"name": "hr"}', [ 'separator' ] ],
[ '{"name": "dt"}', [ 'term' ] ],
[ '{"name": "dfn"}', [ 'term' ] ],
[ '{"name": "textarea"}', [ 'textbox' ] ],
[ '{"name": "input", "attributes": [ {"name": "type", "value": "text"}] }', [ 'textbox' ] ],
]
```
The map of elements to roles is keyed by an HTML concept. An HTML concept corresponds to the `baseConcepts` and `relatedConcepts` of an ARIA role. Concepts exist in the context of a `module`: HTML, XForms, Dublin Core, for example. The concept representation is an object literal with a name property (the element name) and an optional attributes array.
The roles are provided in a [Set](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Set).
### Role to element
```javascript
import { roleElements } from 'aria-query';
```
ARIA roles are mapped to the HTML Elements with the same inherent role. Some roles, such as `columnheader` are only mapped to an HTML element that expresses specific attributes. In the case of `<input>`, the element often requires a `type` attribute to map to an ARIA role.
```javascript
[
[ 'article', [ {"name": "article"} ] ],
[ 'button', [ {"name": "button"} ] ],
[ 'cell', [ {"name": "td"} ] ],
[ 'checkbox', [ {"name": "input", "attributes": [ {"name": "type", "value": "checkbox"}] } ] ],
[ 'columnheader', [ {"name": "th"} ] ],
[ 'combobox', [ {"name": "select"} ] ],
[ 'command', [ {"name": "menuitem"} ] ],
[ 'definition', [ {"name": "dd"}', '{"name": "dfn"} ] ],
[ 'figure', [ {"name": "figure"} ] ],
[ 'form', [ {"name": "form"} ] ],
[ 'grid', [ {"name": "table"} ] ],
[ 'gridcell', [ {"name": "td"} ] ],
[ 'group', [ {"name": "fieldset"} ] ],
[ 'heading', [ {"name": "h1"}', '{"name": "h2"}', '{"name": "h3"}', '{"name": "h4"}', '{"name": "h5"}', '{"name": "h6"} ] ],
[ 'img', [ {"name": "img"} ] ],
[ 'link', [ {"name": "a"}', '{"name": "link"} ] ],
[ 'list', [ {"name": "ol"}', '{"name": "ul"} ] ],
[ 'listbox', [ {"name": "select"} ] ],
[ 'listitem', [ {"name": "li"} ] ],
[ 'menuitem', [ {"name": "menuitem"} ] ],
[ 'navigation', [ {"name": "nav"} ] ],
[ 'option', [ {"name": "option"} ] ],
[ 'radio', [ {"name": "input", "attributes": [ {"name": "type", "value": "radio"}] } ] ],
[ 'region', [ {"name": "frame"} ] ],
[ 'roletype', [ {"name": "rel"} ] ],
[ 'row', [ {"name": "tr"} ] ],
[ 'rowgroup', [ {"name": "tbody"}', '{"name": "tfoot"}', '{"name": "thead"} ] ],
[ 'rowheader', [ {"name": "th", "attributes": [ {"name": "scope", "value": "row"}] }, {"name": "th", "attributes": [ {"name": "scope", "value": "rowgroup"}] } ] ],
[ 'searchbox', [ {"name": "input", "attributes": [ {"name": "type", "value": "search"}] } ] ],
[ 'separator', [ {"name": "hr"} ] ],
[ 'table', [ {"name": "table"} ] ],
[ 'term', [ {"name": "dt"} ] ],
[ 'textbox', [ {"name": "textarea"}', '{"name": "input", "attributes": [ {"name": "type", "value": "text"}] } ] ],
]
```
## License
Copyright (c) 2021 A11yance

713
Readme.md Normal file
View File

@@ -0,0 +1,713 @@
# Commander.js
[![Build Status](https://api.travis-ci.org/tj/commander.js.svg?branch=master)](http://travis-ci.org/tj/commander.js)
[![NPM Version](http://img.shields.io/npm/v/commander.svg?style=flat)](https://www.npmjs.org/package/commander)
[![NPM Downloads](https://img.shields.io/npm/dm/commander.svg?style=flat)](https://npmcharts.com/compare/commander?minimal=true)
[![Install Size](https://packagephobia.now.sh/badge?p=commander)](https://packagephobia.now.sh/result?p=commander)
The complete solution for [node.js](http://nodejs.org) command-line interfaces, inspired by Ruby's [commander](https://github.com/commander-rb/commander).
Read this in other languages: English | [简体中文](./Readme_zh-CN.md)
- [Commander.js](#commanderjs)
- [Installation](#installation)
- [Declaring program variable](#declaring-program-variable)
- [Options](#options)
- [Common option types, boolean and value](#common-option-types-boolean-and-value)
- [Default option value](#default-option-value)
- [Other option types, negatable boolean and flag|value](#other-option-types-negatable-boolean-and-flagvalue)
- [Custom option processing](#custom-option-processing)
- [Required option](#required-option)
- [Version option](#version-option)
- [Commands](#commands)
- [Specify the argument syntax](#specify-the-argument-syntax)
- [Action handler (sub)commands](#action-handler-subcommands)
- [Git-style executable (sub)commands](#git-style-executable-subcommands)
- [Automated --help](#automated---help)
- [Custom help](#custom-help)
- [.usage and .name](#usage-and-name)
- [.outputHelp(cb)](#outputhelpcb)
- [.helpOption(flags, description)](#helpoptionflags-description)
- [.help(cb)](#helpcb)
- [Custom event listeners](#custom-event-listeners)
- [Bits and pieces](#bits-and-pieces)
- [Avoiding option name clashes](#avoiding-option-name-clashes)
- [TypeScript](#typescript)
- [Node options such as --harmony](#node-options-such-as---harmony)
- [Node debugging](#node-debugging)
- [Override exit handling](#override-exit-handling)
- [Examples](#examples)
- [License](#license)
- [Support](#support)
- [Commander for enterprise](#commander-for-enterprise)
## Installation
```bash
npm install commander
```
## Declaring _program_ variable
Commander exports a global object which is convenient for quick programs.
This is used in the examples in this README for brevity.
```js
const program = require('commander');
program.version('0.0.1');
```
For larger programs which may use commander in multiple ways, including unit testing, it is better to create a local Command object to use.
```js
const commander = require('commander');
const program = new commander.Command();
program.version('0.0.1');
```
## Options
Options are defined with the `.option()` method, also serving as documentation for the options. Each option can have a short flag (single character) and a long name, separated by a comma or space.
The options can be accessed as properties on the Command object. Multi-word options such as "--template-engine" are camel-cased, becoming `program.templateEngine` etc. Multiple short flags may be combined as a single arg, for example `-abc` is equivalent to `-a -b -c`.
See also optional new behaviour to [avoid name clashes](#avoiding-option-name-clashes).
### Common option types, boolean and value
The two most used option types are a boolean flag, and an option which takes a value (declared using angle brackets). Both are `undefined` unless specified on command line.
```js
const program = require('commander');
program
.option('-d, --debug', 'output extra debugging')
.option('-s, --small', 'small pizza size')
.option('-p, --pizza-type <type>', 'flavour of pizza');
program.parse(process.argv);
if (program.debug) console.log(program.opts());
console.log('pizza details:');
if (program.small) console.log('- small pizza size');
if (program.pizzaType) console.log(`- ${program.pizzaType}`);
```
```bash
$ pizza-options -d
{ debug: true, small: undefined, pizzaType: undefined }
pizza details:
$ pizza-options -p
error: option '-p, --pizza-type <type>' argument missing
$ pizza-options -ds -p vegetarian
{ debug: true, small: true, pizzaType: 'vegetarian' }
pizza details:
- small pizza size
- vegetarian
$ pizza-options --pizza-type=cheese
pizza details:
- cheese
```
`program.parse(arguments)` processes the arguments, leaving any args not consumed by the options as the `program.args` array.
### Default option value
You can specify a default value for an option which takes a value.
```js
const program = require('commander');
program
.option('-c, --cheese <type>', 'add the specified type of cheese', 'blue');
program.parse(process.argv);
console.log(`cheese: ${program.cheese}`);
```
```bash
$ pizza-options
cheese: blue
$ pizza-options --cheese stilton
cheese: stilton
```
### Other option types, negatable boolean and flag|value
You can specify a boolean option long name with a leading `no-` to set the option value to false when used.
Defined alone this also makes the option true by default.
If you define `--foo` first, adding `--no-foo` does not change the default value from what it would
otherwise be. You can specify a default boolean value for a boolean flag and it can be overridden on command line.
```js
const program = require('commander');
program
.option('--no-sauce', 'Remove sauce')
.option('--cheese <flavour>', 'cheese flavour', 'mozzarella')
.option('--no-cheese', 'plain with no cheese')
.parse(process.argv);
const sauceStr = program.sauce ? 'sauce' : 'no sauce';
const cheeseStr = (program.cheese === false) ? 'no cheese' : `${program.cheese} cheese`;
console.log(`You ordered a pizza with ${sauceStr} and ${cheeseStr}`);
```
```bash
$ pizza-options
You ordered a pizza with sauce and mozzarella cheese
$ pizza-options --sauce
error: unknown option '--sauce'
$ pizza-options --cheese=blue
You ordered a pizza with sauce and blue cheese
$ pizza-options --no-sauce --no-cheese
You ordered a pizza with no sauce and no cheese
```
You can specify an option which functions as a flag but may also take a value (declared using square brackets).
```js
const program = require('commander');
program
.option('-c, --cheese [type]', 'Add cheese with optional type');
program.parse(process.argv);
if (program.cheese === undefined) console.log('no cheese');
else if (program.cheese === true) console.log('add cheese');
else console.log(`add cheese type ${program.cheese}`);
```
```bash
$ pizza-options
no cheese
$ pizza-options --cheese
add cheese
$ pizza-options --cheese mozzarella
add cheese type mozzarella
```
### Custom option processing
You may specify a function to do custom processing of option values. The callback function receives two parameters, the user specified value and the
previous value for the option. It returns the new value for the option.
This allows you to coerce the option value to the desired type, or accumulate values, or do entirely custom processing.
You can optionally specify the default/starting value for the option after the function.
```js
const program = require('commander');
function myParseInt(value, dummyPrevious) {
// parseInt takes a string and an optional radix
return parseInt(value);
}
function increaseVerbosity(dummyValue, previous) {
return previous + 1;
}
function collect(value, previous) {
return previous.concat([value]);
}
function commaSeparatedList(value, dummyPrevious) {
return value.split(',');
}
program
.option('-f, --float <number>', 'float argument', parseFloat)
.option('-i, --integer <number>', 'integer argument', myParseInt)
.option('-v, --verbose', 'verbosity that can be increased', increaseVerbosity, 0)
.option('-c, --collect <value>', 'repeatable value', collect, [])
.option('-l, --list <items>', 'comma separated list', commaSeparatedList)
;
program.parse(process.argv);
if (program.float !== undefined) console.log(`float: ${program.float}`);
if (program.integer !== undefined) console.log(`integer: ${program.integer}`);
if (program.verbose > 0) console.log(`verbosity: ${program.verbose}`);
if (program.collect.length > 0) console.log(program.collect);
if (program.list !== undefined) console.log(program.list);
```
```bash
$ custom -f 1e2
float: 100
$ custom --integer 2
integer: 2
$ custom -v -v -v
verbose: 3
$ custom -c a -c b -c c
[ 'a', 'b', 'c' ]
$ custom --list x,y,z
[ 'x', 'y', 'z' ]
```
### Required option
You may specify a required (mandatory) option using `.requiredOption`. The option must be specified on the command line, or by having a default value. The method is otherwise the same as `.option` in format, taking flags and description, and optional default value or custom processing.
```js
const program = require('commander');
program
.requiredOption('-c, --cheese <type>', 'pizza must have cheese');
program.parse(process.argv);
```
```
$ pizza
error: required option '-c, --cheese <type>' not specified
```
### Version option
The optional `version` method adds handling for displaying the command version. The default option flags are `-V` and `--version`, and when present the command prints the version number and exits.
```js
program.version('0.0.1');
```
```bash
$ ./examples/pizza -V
0.0.1
```
You may change the flags and description by passing additional parameters to the `version` method, using
the same syntax for flags as the `option` method. The version flags can be named anything, but a long name is required.
```js
program.version('0.0.1', '-v, --vers', 'output the current version');
```
## Commands
You can specify (sub)commands for your top-level command using `.command`. There are two ways these can be implemented: using an action handler attached to the command, or as a separate executable file (described in more detail later). In the first parameter to `.command` you specify the command name and any command arguments. The arguments may be `<required>` or `[optional]`, and the last argument may also be `variadic...`.
For example:
```js
// Command implemented using action handler (description is supplied separately to `.command`)
// Returns new command for configuring.
program
.command('clone <source> [destination]')
.description('clone a repository into a newly created directory')
.action((source, destination) => {
console.log('clone command called');
});
// Command implemented using separate executable file (description is second parameter to `.command`)
// Returns top-level command for adding more commands.
program
.command('start <service>', 'start named service')
.command('stop [service]', 'stop named service, or all if no name supplied');
```
### Specify the argument syntax
You use `.arguments` to specify the arguments for the top-level command, and for subcommands they are included in the `.command` call. Angled brackets (e.g. `<required>`) indicate required input. Square brackets (e.g. `[optional]`) indicate optional input.
```js
const program = require('commander');
program
.version('0.1.0')
.arguments('<cmd> [env]')
.action(function (cmd, env) {
cmdValue = cmd;
envValue = env;
});
program.parse(process.argv);
if (typeof cmdValue === 'undefined') {
console.error('no command given!');
process.exit(1);
}
console.log('command:', cmdValue);
console.log('environment:', envValue || "no environment given");
```
The last argument of a command can be variadic, and only the last argument. To make an argument variadic you
append `...` to the argument name. For example:
```js
const program = require('commander');
program
.version('0.1.0')
.command('rmdir <dir> [otherDirs...]')
.action(function (dir, otherDirs) {
console.log('rmdir %s', dir);
if (otherDirs) {
otherDirs.forEach(function (oDir) {
console.log('rmdir %s', oDir);
});
}
});
program.parse(process.argv);
```
The variadic argument is passed to the action handler as an array. (And this also applies to `program.args`.)
### Action handler (sub)commands
You can add options to a command that uses an action handler.
The action handler gets passed a parameter for each argument you declared, and one additional argument which is the
command object itself. This command argument has the values for the command-specific options added as properties.
```js
const program = require('commander');
program
.command('rm <dir>')
.option('-r, --recursive', 'Remove recursively')
.action(function (dir, cmdObj) {
console.log('remove ' + dir + (cmdObj.recursive ? ' recursively' : ''))
})
program.parse(process.argv)
```
You may supply an `async` action handler, in which case you call `.parseAsync` rather than `.parse`.
```js
async function run() { /* code goes here */ }
async function main() {
program
.command('run')
.action(run);
await program.parseAsync(process.argv);
}
```
A command's options on the command line are validated when the command is used. Any unknown options will be reported as an error. However, if an action-based command does not define an action, then the options are not validated.
Configuration options can be passed with the call to `.command()`. Specifying `true` for `opts.noHelp` will remove the command from the generated help output.
### Git-style executable (sub)commands
When `.command()` is invoked with a description argument, this tells commander that you're going to use separate executables for sub-commands, much like `git(1)` and other popular tools.
Commander will search the executables in the directory of the entry script (like `./examples/pm`) with the name `program-subcommand`, like `pm-install`, `pm-search`.
You can specify a custom name with the `executableFile` configuration option.
You handle the options for an executable (sub)command in the executable, and don't declare them at the top-level.
```js
// file: ./examples/pm
const program = require('commander');
program
.version('0.1.0')
.command('install [name]', 'install one or more packages')
.command('search [query]', 'search with optional query')
.command('update', 'update installed packages', {executableFile: 'myUpdateSubCommand'})
.command('list', 'list packages installed', {isDefault: true})
.parse(process.argv);
```
Configuration options can be passed with the call to `.command()`. Specifying `true` for `opts.noHelp` will remove the command from the generated help output. Specifying `true` for `opts.isDefault` will run the subcommand if no other subcommand is specified.
Specifying a name with `executableFile` will override the default constructed name.
If the program is designed to be installed globally, make sure the executables have proper modes, like `755`.
## Automated --help
The help information is auto-generated based on the information commander already knows about your program, so the following `--help` info is for free:
```bash
$ ./examples/pizza --help
Usage: pizza [options]
An application for pizzas ordering
Options:
-V, --version output the version number
-p, --peppers Add peppers
-P, --pineapple Add pineapple
-b, --bbq Add bbq sauce
-c, --cheese <type> Add the specified type of cheese (default: "marble")
-C, --no-cheese You do not want any cheese
-h, --help output usage information
```
### Custom help
You can display arbitrary `-h, --help` information
by listening for "--help". Commander will automatically
exit once you are done so that the remainder of your program
does not execute causing undesired behaviors, for example
in the following executable "stuff" will not output when
`--help` is used.
```js
#!/usr/bin/env node
const program = require('commander');
program
.version('0.1.0')
.option('-f, --foo', 'enable some foo')
.option('-b, --bar', 'enable some bar')
.option('-B, --baz', 'enable some baz');
// must be before .parse() since
// node's emit() is immediate
program.on('--help', function(){
console.log('')
console.log('Examples:');
console.log(' $ custom-help --help');
console.log(' $ custom-help -h');
});
program.parse(process.argv);
console.log('stuff');
```
Yields the following help output when `node script-name.js -h` or `node script-name.js --help` are run:
```Text
Usage: custom-help [options]
Options:
-h, --help output usage information
-V, --version output the version number
-f, --foo enable some foo
-b, --bar enable some bar
-B, --baz enable some baz
Examples:
$ custom-help --help
$ custom-help -h
```
### .usage and .name
These allow you to customise the usage description in the first line of the help. The name is otherwise
deduced from the (full) program arguments. Given:
```js
program
.name("my-command")
.usage("[global options] command")
```
The help will start with:
```Text
Usage: my-command [global options] command
```
### .outputHelp(cb)
Output help information without exiting.
Optional callback cb allows post-processing of help text before it is displayed.
If you want to display help by default (e.g. if no command was provided), you can use something like:
```js
const program = require('commander');
const colors = require('colors');
program
.version('0.1.0')
.command('getstream [url]', 'get stream URL')
.parse(process.argv);
if (!process.argv.slice(2).length) {
program.outputHelp(make_red);
}
function make_red(txt) {
return colors.red(txt); //display the help text in red on the console
}
```
### .helpOption(flags, description)
Override the default help flags and description.
```js
program
.helpOption('-e, --HELP', 'read more information');
```
### .help(cb)
Output help information and exit immediately.
Optional callback cb allows post-processing of help text before it is displayed.
## Custom event listeners
You can execute custom actions by listening to command and option events.
```js
program.on('option:verbose', function () {
process.env.VERBOSE = this.verbose;
});
// error on unknown commands
program.on('command:*', function () {
console.error('Invalid command: %s\nSee --help for a list of available commands.', program.args.join(' '));
process.exit(1);
});
```
## Bits and pieces
### Avoiding option name clashes
The original and default behaviour is that the option values are stored
as properties on the program, and the action handler is passed a
command object with the options values stored as properties.
This is very convenient to code, but the downside is possible clashes with
existing properties of Command.
There are two new routines to change the behaviour, and the default behaviour may change in the future:
- `storeOptionsAsProperties`: whether to store option values as properties on command object, or store separately (specify false) and access using `.opts()`
- `passCommandToAction`: whether to pass command to action handler,
or just the options (specify false)
```js
// file: ./examples/storeOptionsAsProperties.action.js
program
.storeOptionsAsProperties(false)
.passCommandToAction(false);
program
.name('my-program-name')
.option('-n,--name <name>');
program
.command('show')
.option('-a,--action <action>')
.action((options) => {
console.log(options.action);
});
program.parse(process.argv);
const programOptions = program.opts();
console.log(programOptions.name);
```
### TypeScript
The Commander package includes its TypeScript Definition file, but also requires the node types which you need to install yourself. e.g.
```bash
npm install commander
npm install --save-dev @types/node
```
If you use `ts-node` and git-style sub-commands written as `.ts` files, you need to call your program through node to get the sub-commands called correctly. e.g.
```bash
node -r ts-node/register pm.ts
```
### Node options such as `--harmony`
You can enable `--harmony` option in two ways:
- Use `#! /usr/bin/env node --harmony` in the sub-commands scripts. (Note Windows does not support this pattern.)
- Use the `--harmony` option when call the command, like `node --harmony examples/pm publish`. The `--harmony` option will be preserved when spawning sub-command process.
### Node debugging
If you are using the node inspector for [debugging](https://nodejs.org/en/docs/guides/debugging-getting-started/) git-style executable (sub)commands using `node --inspect` et al,
the inspector port is incremented by 1 for the spawned subcommand.
### Override exit handling
By default Commander calls `process.exit` when it detects errors, or after displaying the help or version. You can override
this behaviour and optionally supply a callback. The default override throws a `CommanderError`.
The override callback is passed a `CommanderError` with properties `exitCode` number, `code` string, and `message`. The default override behaviour is to throw the error, except for async handling of executable subcommand completion which carries on. The normal display of error messages or version or help
is not affected by the override which is called after the display.
``` js
program.exitOverride();
try {
program.parse(process.argv);
} catch (err) {
// custom processing...
}
```
## Examples
```js
const program = require('commander');
program
.version('0.1.0')
.option('-C, --chdir <path>', 'change the working directory')
.option('-c, --config <path>', 'set config path. defaults to ./deploy.conf')
.option('-T, --no-tests', 'ignore test hook');
program
.command('setup [env]')
.description('run setup commands for all envs')
.option("-s, --setup_mode [mode]", "Which setup mode to use")
.action(function(env, options){
const mode = options.setup_mode || "normal";
env = env || 'all';
console.log('setup for %s env(s) with %s mode', env, mode);
});
program
.command('exec <cmd>')
.alias('ex')
.description('execute the given remote cmd')
.option("-e, --exec_mode <mode>", "Which exec mode to use")
.action(function(cmd, options){
console.log('exec "%s" using %s mode', cmd, options.exec_mode);
}).on('--help', function() {
console.log('');
console.log('Examples:');
console.log('');
console.log(' $ deploy exec sequential');
console.log(' $ deploy exec async');
});
program
.command('*')
.action(function(env){
console.log('deploying "%s"', env);
});
program.parse(process.argv);
```
More Demos can be found in the [examples](https://github.com/tj/commander.js/tree/master/examples) directory.
## License
[MIT](https://github.com/tj/commander.js/blob/master/LICENSE)
## Support
Commander 4.x is supported on Node 8 and above, and is likely to work with Node 6 but not tested.
(For versions of Node below Node 6, use Commander 3.x or 2.x.)
The main forum for free and community support is the project [Issues](https://github.com/tj/commander.js/issues) on GitHub.
### Commander for enterprise
Available as part of the Tidelift Subscription
The maintainers of Commander and thousands of other packages are working with Tidelift to deliver commercial support and maintenance for the open source dependencies you use to build your applications. Save time, reduce risk, and improve code health, while paying the maintainers of the exact dependencies you use. [Learn more.](https://tidelift.com/subscription/pkg/npm-commander?utm_source=npm-commander&utm_medium=referral&utm_campaign=enterprise&utm_term=repo)

15
SECURITY.md Normal file
View File

@@ -0,0 +1,15 @@
# Security Policy
## Supported Versions
Use this section to tell people about which versions of your project are
currently being supported with security updates.
| Version | Supported |
| ------- | ------------------ |
| 1.x | :white_check_mark: |
| < 1.0 | :x: |
## Reporting a Vulnerability
Please report all vulnerabilities at [https://github.com/mcollina/fastq/security](https://github.com/mcollina/fastq/security).

BIN
__init__.cpython-311.pyc Normal file

Binary file not shown.

BIN
__init__.py Normal file

Binary file not shown.

1
_svelte_metadata.json Normal file
View File

@@ -0,0 +1 @@
{"compilerOptions":{"css":"external","dev":true,"hmr":true},"configFile":"C:\\Users\\User\\Documents\\Docs-estadias-202526\\dock\\control_mve_frontend\\svelte.config.js","extensions":[".svelte"],"preprocess":{"name":"vite-preprocess","style":"async ({ attributes, content, filename = '' }) => {\n\t\tconst ext = attributes.lang ? `.${attributes.lang}` : '.css';\n\t\tif (attributes.lang && !isCSSRequest(ext)) return;\n\t\tif (!cssTransform) {\n\t\t\tcssTransform = createCssTransform(style, config).then((t) => (cssTransform = t));\n\t\t}\n\t\tconst transform = await cssTransform;\n\t\tconst suffix = `${lang_sep}${ext}`;\n\t\tconst moduleId = `${filename}${suffix}`;\n\t\tconst { code, map, deps } = await transform(content, moduleId);\n\t\tremoveLangSuffix(map, suffix);\n\t\tmapToRelative(map, filename);\n\t\tconst dependencies = deps ? Array.from(deps).filter((d) => !d.endsWith(suffix)) : undefined;\n\t\treturn {\n\t\t\tcode,\n\t\t\tmap: map ?? undefined,\n\t\t\tdependencies\n\t\t};\n\t}"}}

Binary file not shown.

View File

@@ -0,0 +1,124 @@
"""agregar tabla usuarios
Revision ID: a3113e7c1b12
Revises:
Create Date: 2025-12-15 19:24:37.318851
"""
from typing import Sequence, Union
from alembic import op
import sqlalchemy as sa
# revision identifiers, used by Alembic.
revision: str = 'a3113e7c1b12'
down_revision: Union[str, None] = None
branch_labels: Union[str, Sequence[str], None] = None
depends_on: Union[str, Sequence[str], None] = None
def upgrade() -> None:
# ### commands auto generated by Alembic - please adjust! ###
op.create_table('clientes',
sa.Column('id', sa.Integer(), nullable=False),
sa.Column('nombre', sa.String(length=255), nullable=False),
sa.Column('email', sa.String(length=255), nullable=False),
sa.Column('rfc', sa.String(length=13), nullable=True),
sa.Column('telefono', sa.String(length=20), nullable=True),
sa.Column('timbres_consumidos', sa.Integer(), nullable=False),
sa.Column('estado', sa.Enum('ACTIVO', 'INACTIVO', 'SUSPENDIDO', name='estadocliente'), nullable=False),
sa.Column('permite_subclientes', sa.Boolean(), nullable=False),
sa.Column('created_at', sa.DateTime(timezone=True), server_default=sa.text('now()'), nullable=True),
sa.Column('updated_at', sa.DateTime(timezone=True), nullable=True),
sa.PrimaryKeyConstraint('id')
)
op.create_index(op.f('ix_clientes_email'), 'clientes', ['email'], unique=True)
op.create_index(op.f('ix_clientes_id'), 'clientes', ['id'], unique=False)
op.create_index(op.f('ix_clientes_rfc'), 'clientes', ['rfc'], unique=True)
op.create_table('usuarios',
sa.Column('id', sa.Integer(), nullable=False),
sa.Column('username', sa.String(length=50), nullable=False),
sa.Column('email', sa.String(length=255), nullable=False),
sa.Column('hashed_password', sa.String(length=255), nullable=False),
sa.Column('nombre_completo', sa.String(length=255), nullable=True),
sa.Column('is_active', sa.Boolean(), nullable=False),
sa.Column('is_superuser', sa.Boolean(), nullable=False),
sa.Column('created_at', sa.DateTime(timezone=True), server_default=sa.text('now()'), nullable=True),
sa.Column('updated_at', sa.DateTime(timezone=True), nullable=True),
sa.Column('last_login', sa.DateTime(timezone=True), nullable=True),
sa.PrimaryKeyConstraint('id')
)
op.create_index(op.f('ix_usuarios_email'), 'usuarios', ['email'], unique=True)
op.create_index(op.f('ix_usuarios_id'), 'usuarios', ['id'], unique=False)
op.create_index(op.f('ix_usuarios_username'), 'usuarios', ['username'], unique=True)
op.create_table('limites_timbres',
sa.Column('id', sa.Integer(), nullable=False),
sa.Column('cliente_id', sa.Integer(), nullable=False),
sa.Column('tipo', sa.Enum('ASIGNACION_INICIAL', 'INCREMENTO', 'DECREMENTO', 'AJUSTE', name='tipolimite'), nullable=False),
sa.Column('cantidad', sa.Integer(), nullable=False),
sa.Column('descripcion', sa.String(length=500), nullable=True),
sa.Column('activo', sa.Integer(), nullable=False),
sa.Column('created_at', sa.DateTime(timezone=True), server_default=sa.text('now()'), nullable=True),
sa.Column('inactivado_at', sa.DateTime(timezone=True), nullable=True),
sa.ForeignKeyConstraint(['cliente_id'], ['clientes.id'], ),
sa.PrimaryKeyConstraint('id')
)
op.create_index(op.f('ix_limites_timbres_id'), 'limites_timbres', ['id'], unique=False)
op.create_table('subclientes',
sa.Column('id', sa.Integer(), nullable=False),
sa.Column('cliente_id', sa.Integer(), nullable=False),
sa.Column('nombre', sa.String(length=255), nullable=False),
sa.Column('email', sa.String(length=255), nullable=False),
sa.Column('rfc', sa.String(length=13), nullable=True),
sa.Column('telefono', sa.String(length=20), nullable=True),
sa.Column('timbres_consumidos', sa.Integer(), nullable=False),
sa.Column('limite_propio', sa.Integer(), nullable=True),
sa.Column('estado', sa.Enum('ACTIVO', 'INACTIVO', 'SUSPENDIDO', name='estadocliente'), nullable=False),
sa.Column('created_at', sa.DateTime(timezone=True), server_default=sa.text('now()'), nullable=True),
sa.Column('updated_at', sa.DateTime(timezone=True), nullable=True),
sa.ForeignKeyConstraint(['cliente_id'], ['clientes.id'], ),
sa.PrimaryKeyConstraint('id')
)
op.create_index(op.f('ix_subclientes_email'), 'subclientes', ['email'], unique=True)
op.create_index(op.f('ix_subclientes_id'), 'subclientes', ['id'], unique=False)
op.create_index(op.f('ix_subclientes_rfc'), 'subclientes', ['rfc'], unique=False)
op.create_table('movimientos_timbres',
sa.Column('id', sa.Integer(), nullable=False),
sa.Column('cliente_id', sa.Integer(), nullable=False),
sa.Column('subcliente_id', sa.Integer(), nullable=True),
sa.Column('tipo', sa.Enum('CONSUMO', 'RECARGA', 'AJUSTE', name='tipomovimiento'), nullable=False),
sa.Column('cantidad', sa.Integer(), nullable=False),
sa.Column('descripcion', sa.String(length=500), nullable=True),
sa.Column('referencia_externa', sa.String(length=255), nullable=True),
sa.Column('balance_cliente', sa.Integer(), nullable=False),
sa.Column('created_at', sa.DateTime(timezone=True), server_default=sa.text('now()'), nullable=True),
sa.ForeignKeyConstraint(['cliente_id'], ['clientes.id'], ),
sa.ForeignKeyConstraint(['subcliente_id'], ['subclientes.id'], ),
sa.PrimaryKeyConstraint('id')
)
op.create_index(op.f('ix_movimientos_timbres_id'), 'movimientos_timbres', ['id'], unique=False)
op.create_index(op.f('ix_movimientos_timbres_referencia_externa'), 'movimientos_timbres', ['referencia_externa'], unique=False)
# ### end Alembic commands ###
def downgrade() -> None:
# ### commands auto generated by Alembic - please adjust! ###
op.drop_index(op.f('ix_movimientos_timbres_referencia_externa'), table_name='movimientos_timbres')
op.drop_index(op.f('ix_movimientos_timbres_id'), table_name='movimientos_timbres')
op.drop_table('movimientos_timbres')
op.drop_index(op.f('ix_subclientes_rfc'), table_name='subclientes')
op.drop_index(op.f('ix_subclientes_id'), table_name='subclientes')
op.drop_index(op.f('ix_subclientes_email'), table_name='subclientes')
op.drop_table('subclientes')
op.drop_index(op.f('ix_limites_timbres_id'), table_name='limites_timbres')
op.drop_table('limites_timbres')
op.drop_index(op.f('ix_usuarios_username'), table_name='usuarios')
op.drop_index(op.f('ix_usuarios_id'), table_name='usuarios')
op.drop_index(op.f('ix_usuarios_email'), table_name='usuarios')
op.drop_table('usuarios')
op.drop_index(op.f('ix_clientes_rfc'), table_name='clientes')
op.drop_index(op.f('ix_clientes_id'), table_name='clientes')
op.drop_index(op.f('ix_clientes_email'), table_name='clientes')
op.drop_table('clientes')
# ### end Alembic commands ###

16
acorn Normal file
View File

@@ -0,0 +1,16 @@
#!/bin/sh
basedir=$(dirname "$(echo "$0" | sed -e 's,\\,/,g')")
case `uname` in
*CYGWIN*|*MINGW*|*MSYS*)
if command -v cygpath > /dev/null 2>&1; then
basedir=`cygpath -w "$basedir"`
fi
;;
esac
if [ -x "$basedir/node" ]; then
exec "$basedir/node" "$basedir/../acorn/bin/acorn" "$@"
else
exec node "$basedir/../acorn/bin/acorn" "$@"
fi

17
acorn.cmd Normal file
View File

@@ -0,0 +1,17 @@
@ECHO off
GOTO start
:find_dp0
SET dp0=%~dp0
EXIT /b
:start
SETLOCAL
CALL :find_dp0
IF EXIST "%dp0%\node.exe" (
SET "_prog=%dp0%\node.exe"
) ELSE (
SET "_prog=node"
SET PATHEXT=%PATHEXT:;.JS;=;%
)
endLocal & goto #_undefined_# 2>NUL || title %COMSPEC% & "%_prog%" "%dp0%\..\acorn\bin\acorn" %*

28
acorn.ps1 Normal file
View File

@@ -0,0 +1,28 @@
#!/usr/bin/env pwsh
$basedir=Split-Path $MyInvocation.MyCommand.Definition -Parent
$exe=""
if ($PSVersionTable.PSVersion -lt "6.0" -or $IsWindows) {
# Fix case when both the Windows and Linux builds of Node
# are installed in the same directory
$exe=".exe"
}
$ret=0
if (Test-Path "$basedir/node$exe") {
# Support pipeline input
if ($MyInvocation.ExpectingInput) {
$input | & "$basedir/node$exe" "$basedir/../acorn/bin/acorn" $args
} else {
& "$basedir/node$exe" "$basedir/../acorn/bin/acorn" $args
}
$ret=$LASTEXITCODE
} else {
# Support pipeline input
if ($MyInvocation.ExpectingInput) {
$input | & "node$exe" "$basedir/../acorn/bin/acorn" $args
} else {
& "node$exe" "$basedir/../acorn/bin/acorn" $args
}
$ret=$LASTEXITCODE
}
exit $ret

114
alembic.ini Normal file
View File

@@ -0,0 +1,114 @@
# A generic, single database configuration.
[alembic]
# path to migration scripts
script_location = alembic
# template used to generate migration file names; The default value is %%(rev)s_%%(slug)s
# Uncomment the line below if you want the files to be prepended with date and time
# file_template = %%(year)d_%%(month).2d_%%(day).2d_%%(hour).2d%%(minute).2d-%%(rev)s_%%(slug)s
# sys.path path, will be prepended to sys.path if present.
# defaults to the current working directory.
prepend_sys_path = .
# timezone to use when rendering the date within the migration file
# as well as the filename.
# If specified, requires the python-dateutil library that can be
# installed by adding `alembic[tz]` to the pip requirements
# string value is passed to dateutil.tz.gettz()
# leave blank for localtime
# timezone =
# max length of characters to apply to the
# "slug" field
# truncate_slug_length = 40
# set to 'true' to run the environment during
# the 'revision' command, regardless of autogenerate
# revision_environment = false
# set to 'true' to allow .pyc and .pyo files without
# a source .py file to be detected as revisions in the
# versions/ directory
# sourceless = false
# version location specification; This defaults
# to alembic/versions. When using multiple version
# directories, initial revisions must be specified with --version-path.
# The path separator used here should be the separator specified by "version_path_separator" below.
# version_locations = %(here)s/bar:%(here)s/bat:alembic/versions
# version path separator; As mentioned above, this is the character used to split
# version_locations. The default within new alembic.ini files is "os", which uses os.pathsep.
# If this key is omitted entirely, it falls back to the legacy behavior of splitting on spaces and/or commas.
# Valid values for version_path_separator are:
#
# version_path_separator = :
# version_path_separator = ;
# version_path_separator = space
version_path_separator = os # Use os.pathsep. Default configuration used for new projects.
# set to 'true' to search source files recursively
# in each "version_locations" directory
# new in Alembic version 1.10
# recursive_version_locations = false
# the output encoding used when revision files
# are written from script.py.mako
# output_encoding = utf-8
sqlalchemy.url = driver://user:pass@localhost/dbname
[post_write_hooks]
# post_write_hooks defines scripts or Python functions that are run
# on newly generated revision scripts. See the documentation for further
# detail and examples
# format using "black" - use the console_scripts runner, against the "black" entrypoint
# hooks = black
# black.type = console_scripts
# black.entrypoint = black
# black.options = -l 79 REVISION_SCRIPT_FILENAME
# lint with attempts to fix using "ruff" - use the exec runner, execute a binary
# hooks = ruff
# ruff.type = exec
# ruff.executable = %(here)s/.venv/bin/ruff
# ruff.options = --fix REVISION_SCRIPT_FILENAME
# Logging configuration
[loggers]
keys = root,sqlalchemy,alembic
[handlers]
keys = console
[formatters]
keys = generic
[logger_root]
level = WARN
handlers = console
qualname =
[logger_sqlalchemy]
level = WARN
handlers =
qualname = sqlalchemy.engine
[logger_alembic]
level = INFO
handlers =
qualname = alembic
[handler_console]
class = StreamHandler
args = (sys.stderr,)
level = NOTSET
formatter = generic
[formatter_generic]
format = %(levelname)-5.5s [%(name)s] %(message)s
datefmt = %H:%M:%S

3
app.css Normal file
View File

@@ -0,0 +1,3 @@
@tailwind base;
@tailwind components;
@tailwind utilities;

15
applypatch-msg.sample Normal file
View File

@@ -0,0 +1,15 @@
#!/bin/sh
#
# An example hook script to check the commit log message taken by
# applypatch from an e-mail message.
#
# The hook should exit with non-zero status after issuing an
# appropriate message if it wants to stop the commit. The hook is
# allowed to edit the commit message file.
#
# To enable this hook, rename this file to "applypatch-msg".
. git-sh-setup
commitmsg="$(git rev-parse --git-path hooks/commit-msg)"
test -x "$commitmsg" && exec "$commitmsg" ${1+"$@"}
:

BIN
auth.cpython-311.pyc Normal file

Binary file not shown.

232
auth.py Normal file
View File

@@ -0,0 +1,232 @@
from fastapi import APIRouter, Depends, HTTPException, status
from sqlalchemy.orm import Session
from datetime import datetime, timedelta
from typing import List
from app.database import get_db
from app.models import Usuario
from app.schemas import (
UsuarioCreate, UsuarioUpdate, UsuarioResponse,
Token, LoginRequest, MessageResponse
)
from app.auth import verify_password, get_password_hash, create_access_token
from app.dependencies import get_current_user, get_current_active_superuser
from app.config import settings
router = APIRouter()
@router.post("/register", response_model=UsuarioResponse, status_code=status.HTTP_201_CREATED)
def register(usuario: UsuarioCreate, db: Session = Depends(get_db)):
"""
Registrar un nuevo usuario (público - primer usuario será superuser)
"""
# Verificar si el username ya existe
if db.query(Usuario).filter(Usuario.username == usuario.username).first():
raise HTTPException(
status_code=status.HTTP_400_BAD_REQUEST,
detail="El username ya está registrado"
)
# Verificar si el email ya existe
if db.query(Usuario).filter(Usuario.email == usuario.email).first():
raise HTTPException(
status_code=status.HTTP_400_BAD_REQUEST,
detail="El email ya está registrado"
)
# Si es el primer usuario, hacerlo superuser
total_usuarios = db.query(Usuario).count()
is_superuser = (total_usuarios == 0)
# Crear usuario
db_usuario = Usuario(
username=usuario.username,
email=usuario.email,
nombre_completo=usuario.nombre_completo,
hashed_password=get_password_hash(usuario.password),
is_superuser=is_superuser
)
db.add(db_usuario)
db.commit()
db.refresh(db_usuario)
return db_usuario
@router.post("/login", response_model=Token)
def login(login_data: LoginRequest, db: Session = Depends(get_db)):
"""
Iniciar sesión y obtener token JWT
"""
user = db.query(Usuario).filter(Usuario.username == login_data.username).first()
if not user or not verify_password(login_data.password, user.hashed_password):
raise HTTPException(
status_code=status.HTTP_401_UNAUTHORIZED,
detail="Usuario o contraseña incorrectos",
headers={"WWW-Authenticate": "Bearer"},
)
if not user.is_active:
raise HTTPException(
status_code=status.HTTP_403_FORBIDDEN,
detail="Usuario inactivo"
)
# Actualizar último login
user.last_login = datetime.utcnow()
db.commit()
# Crear token
access_token_expires = timedelta(minutes=settings.ACCESS_TOKEN_EXPIRE_MINUTES)
access_token = create_access_token(
data={"sub": user.username}, expires_delta=access_token_expires
)
return {"access_token": access_token, "token_type": "bearer"}
@router.get("/me", response_model=UsuarioResponse)
def read_users_me(current_user: Usuario = Depends(get_current_user)):
"""
Obtener información del usuario actual
"""
return current_user
@router.put("/me", response_model=UsuarioResponse)
def update_user_me(
usuario_update: UsuarioUpdate,
current_user: Usuario = Depends(get_current_user),
db: Session = Depends(get_db)
):
"""
Actualizar información del usuario actual
"""
update_data = usuario_update.model_dump(exclude_unset=True)
# Verificar email único si se actualiza
if "email" in update_data and update_data["email"] != current_user.email:
if db.query(Usuario).filter(Usuario.email == update_data["email"]).first():
raise HTTPException(
status_code=status.HTTP_400_BAD_REQUEST,
detail="El email ya está registrado"
)
# Si hay password, hashear
if "password" in update_data:
update_data["hashed_password"] = get_password_hash(update_data.pop("password"))
for field, value in update_data.items():
setattr(current_user, field, value)
db.commit()
db.refresh(current_user)
return current_user
@router.get("/", response_model=List[UsuarioResponse])
def list_users(
skip: int = 0,
limit: int = 100,
current_user: Usuario = Depends(get_current_active_superuser),
db: Session = Depends(get_db)
):
"""
Listar todos los usuarios (solo superuser)
"""
usuarios = db.query(Usuario).offset(skip).limit(limit).all()
return usuarios
@router.get("/{usuario_id}", response_model=UsuarioResponse)
def get_user(
usuario_id: int,
current_user: Usuario = Depends(get_current_active_superuser),
db: Session = Depends(get_db)
):
"""
Obtener un usuario por ID (solo superuser)
"""
usuario = db.query(Usuario).filter(Usuario.id == usuario_id).first()
if not usuario:
raise HTTPException(
status_code=status.HTTP_404_NOT_FOUND,
detail="Usuario no encontrado"
)
return usuario
@router.put("/{usuario_id}", response_model=UsuarioResponse)
def update_user(
usuario_id: int,
usuario_update: UsuarioUpdate,
current_user: Usuario = Depends(get_current_active_superuser),
db: Session = Depends(get_db)
):
"""
Actualizar un usuario (solo superuser)
"""
usuario = db.query(Usuario).filter(Usuario.id == usuario_id).first()
if not usuario:
raise HTTPException(
status_code=status.HTTP_404_NOT_FOUND,
detail="Usuario no encontrado"
)
update_data = usuario_update.model_dump(exclude_unset=True)
# Verificar email único si se actualiza
if "email" in update_data and update_data["email"] != usuario.email:
if db.query(Usuario).filter(Usuario.email == update_data["email"]).first():
raise HTTPException(
status_code=status.HTTP_400_BAD_REQUEST,
detail="El email ya está registrado"
)
# Si hay password, hashear
if "password" in update_data:
update_data["hashed_password"] = get_password_hash(update_data.pop("password"))
for field, value in update_data.items():
setattr(usuario, field, value)
db.commit()
db.refresh(usuario)
return usuario
@router.delete("/{usuario_id}", response_model=MessageResponse)
def delete_user(
usuario_id: int,
current_user: Usuario = Depends(get_current_active_superuser),
db: Session = Depends(get_db)
):
"""
Eliminar un usuario (solo superuser)
"""
usuario = db.query(Usuario).filter(Usuario.id == usuario_id).first()
if not usuario:
raise HTTPException(
status_code=status.HTTP_404_NOT_FOUND,
detail="Usuario no encontrado"
)
# No permitir eliminar el propio usuario
if usuario.id == current_user.id:
raise HTTPException(
status_code=status.HTTP_400_BAD_REQUEST,
detail="No puedes eliminar tu propio usuario"
)
db.delete(usuario)
db.commit()
return {"message": f"Usuario {usuario.username} eliminado exitosamente"}

16
autoprefixer Normal file
View File

@@ -0,0 +1,16 @@
#!/bin/sh
basedir=$(dirname "$(echo "$0" | sed -e 's,\\,/,g')")
case `uname` in
*CYGWIN*|*MINGW*|*MSYS*)
if command -v cygpath > /dev/null 2>&1; then
basedir=`cygpath -w "$basedir"`
fi
;;
esac
if [ -x "$basedir/node" ]; then
exec "$basedir/node" "$basedir/../autoprefixer/bin/autoprefixer" "$@"
else
exec node "$basedir/../autoprefixer/bin/autoprefixer" "$@"
fi

17
autoprefixer.cmd Normal file
View File

@@ -0,0 +1,17 @@
@ECHO off
GOTO start
:find_dp0
SET dp0=%~dp0
EXIT /b
:start
SETLOCAL
CALL :find_dp0
IF EXIST "%dp0%\node.exe" (
SET "_prog=%dp0%\node.exe"
) ELSE (
SET "_prog=node"
SET PATHEXT=%PATHEXT:;.JS;=;%
)
endLocal & goto #_undefined_# 2>NUL || title %COMSPEC% & "%_prog%" "%dp0%\..\autoprefixer\bin\autoprefixer" %*

28
autoprefixer.ps1 Normal file
View File

@@ -0,0 +1,28 @@
#!/usr/bin/env pwsh
$basedir=Split-Path $MyInvocation.MyCommand.Definition -Parent
$exe=""
if ($PSVersionTable.PSVersion -lt "6.0" -or $IsWindows) {
# Fix case when both the Windows and Linux builds of Node
# are installed in the same directory
$exe=".exe"
}
$ret=0
if (Test-Path "$basedir/node$exe") {
# Support pipeline input
if ($MyInvocation.ExpectingInput) {
$input | & "$basedir/node$exe" "$basedir/../autoprefixer/bin/autoprefixer" $args
} else {
& "$basedir/node$exe" "$basedir/../autoprefixer/bin/autoprefixer" $args
}
$ret=$LASTEXITCODE
} else {
# Support pipeline input
if ($MyInvocation.ExpectingInput) {
$input | & "node$exe" "$basedir/../autoprefixer/bin/autoprefixer" $args
} else {
& "node$exe" "$basedir/../autoprefixer/bin/autoprefixer" $args
}
$ret=$LASTEXITCODE
}
exit $ret

16
baseline-browser-mapping Normal file
View File

@@ -0,0 +1,16 @@
#!/bin/sh
basedir=$(dirname "$(echo "$0" | sed -e 's,\\,/,g')")
case `uname` in
*CYGWIN*|*MINGW*|*MSYS*)
if command -v cygpath > /dev/null 2>&1; then
basedir=`cygpath -w "$basedir"`
fi
;;
esac
if [ -x "$basedir/node" ]; then
exec "$basedir/node" "$basedir/../baseline-browser-mapping/dist/cli.js" "$@"
else
exec node "$basedir/../baseline-browser-mapping/dist/cli.js" "$@"
fi

View File

@@ -0,0 +1,17 @@
@ECHO off
GOTO start
:find_dp0
SET dp0=%~dp0
EXIT /b
:start
SETLOCAL
CALL :find_dp0
IF EXIST "%dp0%\node.exe" (
SET "_prog=%dp0%\node.exe"
) ELSE (
SET "_prog=node"
SET PATHEXT=%PATHEXT:;.JS;=;%
)
endLocal & goto #_undefined_# 2>NUL || title %COMSPEC% & "%_prog%" "%dp0%\..\baseline-browser-mapping\dist\cli.js" %*

View File

@@ -0,0 +1,28 @@
#!/usr/bin/env pwsh
$basedir=Split-Path $MyInvocation.MyCommand.Definition -Parent
$exe=""
if ($PSVersionTable.PSVersion -lt "6.0" -or $IsWindows) {
# Fix case when both the Windows and Linux builds of Node
# are installed in the same directory
$exe=".exe"
}
$ret=0
if (Test-Path "$basedir/node$exe") {
# Support pipeline input
if ($MyInvocation.ExpectingInput) {
$input | & "$basedir/node$exe" "$basedir/../baseline-browser-mapping/dist/cli.js" $args
} else {
& "$basedir/node$exe" "$basedir/../baseline-browser-mapping/dist/cli.js" $args
}
$ret=$LASTEXITCODE
} else {
# Support pipeline input
if ($MyInvocation.ExpectingInput) {
$input | & "node$exe" "$basedir/../baseline-browser-mapping/dist/cli.js" $args
} else {
& "node$exe" "$basedir/../baseline-browser-mapping/dist/cli.js" $args
}
$ret=$LASTEXITCODE
}
exit $ret

66
bench.js Normal file
View File

@@ -0,0 +1,66 @@
'use strict'
const max = 1000000
const fastqueue = require('./')(worker, 1)
const { promisify } = require('util')
const immediate = promisify(setImmediate)
const qPromise = require('./').promise(immediate, 1)
const async = require('async')
const neo = require('neo-async')
const asyncqueue = async.queue(worker, 1)
const neoqueue = neo.queue(worker, 1)
function bench (func, done) {
const key = max + '*' + func.name
let count = -1
console.time(key)
end()
function end () {
if (++count < max) {
func(end)
} else {
console.timeEnd(key)
if (done) {
done()
}
}
}
}
function benchFastQ (done) {
fastqueue.push(42, done)
}
function benchAsyncQueue (done) {
asyncqueue.push(42, done)
}
function benchNeoQueue (done) {
neoqueue.push(42, done)
}
function worker (arg, cb) {
setImmediate(cb)
}
function benchSetImmediate (cb) {
worker(42, cb)
}
function benchFastQPromise (done) {
qPromise.push(42).then(function () { done() }, done)
}
function runBench (done) {
async.eachSeries([
benchSetImmediate,
benchFastQ,
benchNeoQueue,
benchAsyncQueue,
benchFastQPromise
], bench, done)
}
runBench(runBench)

263
binary-extensions.json Normal file
View File

@@ -0,0 +1,263 @@
[
"3dm",
"3ds",
"3g2",
"3gp",
"7z",
"a",
"aac",
"adp",
"afdesign",
"afphoto",
"afpub",
"ai",
"aif",
"aiff",
"alz",
"ape",
"apk",
"appimage",
"ar",
"arj",
"asf",
"au",
"avi",
"bak",
"baml",
"bh",
"bin",
"bk",
"bmp",
"btif",
"bz2",
"bzip2",
"cab",
"caf",
"cgm",
"class",
"cmx",
"cpio",
"cr2",
"cur",
"dat",
"dcm",
"deb",
"dex",
"djvu",
"dll",
"dmg",
"dng",
"doc",
"docm",
"docx",
"dot",
"dotm",
"dra",
"DS_Store",
"dsk",
"dts",
"dtshd",
"dvb",
"dwg",
"dxf",
"ecelp4800",
"ecelp7470",
"ecelp9600",
"egg",
"eol",
"eot",
"epub",
"exe",
"f4v",
"fbs",
"fh",
"fla",
"flac",
"flatpak",
"fli",
"flv",
"fpx",
"fst",
"fvt",
"g3",
"gh",
"gif",
"graffle",
"gz",
"gzip",
"h261",
"h263",
"h264",
"icns",
"ico",
"ief",
"img",
"ipa",
"iso",
"jar",
"jpeg",
"jpg",
"jpgv",
"jpm",
"jxr",
"key",
"ktx",
"lha",
"lib",
"lvp",
"lz",
"lzh",
"lzma",
"lzo",
"m3u",
"m4a",
"m4v",
"mar",
"mdi",
"mht",
"mid",
"midi",
"mj2",
"mka",
"mkv",
"mmr",
"mng",
"mobi",
"mov",
"movie",
"mp3",
"mp4",
"mp4a",
"mpeg",
"mpg",
"mpga",
"mxu",
"nef",
"npx",
"numbers",
"nupkg",
"o",
"odp",
"ods",
"odt",
"oga",
"ogg",
"ogv",
"otf",
"ott",
"pages",
"pbm",
"pcx",
"pdb",
"pdf",
"pea",
"pgm",
"pic",
"png",
"pnm",
"pot",
"potm",
"potx",
"ppa",
"ppam",
"ppm",
"pps",
"ppsm",
"ppsx",
"ppt",
"pptm",
"pptx",
"psd",
"pya",
"pyc",
"pyo",
"pyv",
"qt",
"rar",
"ras",
"raw",
"resources",
"rgb",
"rip",
"rlc",
"rmf",
"rmvb",
"rpm",
"rtf",
"rz",
"s3m",
"s7z",
"scpt",
"sgi",
"shar",
"snap",
"sil",
"sketch",
"slk",
"smv",
"snk",
"so",
"stl",
"suo",
"sub",
"swf",
"tar",
"tbz",
"tbz2",
"tga",
"tgz",
"thmx",
"tif",
"tiff",
"tlz",
"ttc",
"ttf",
"txz",
"udf",
"uvh",
"uvi",
"uvm",
"uvp",
"uvs",
"uvu",
"viv",
"vob",
"war",
"wav",
"wax",
"wbmp",
"wdp",
"weba",
"webm",
"webp",
"whl",
"wim",
"wm",
"wma",
"wmv",
"wmx",
"woff",
"woff2",
"wrm",
"wvx",
"xbm",
"xif",
"xla",
"xlam",
"xls",
"xlsb",
"xlsm",
"xlsx",
"xlt",
"xltm",
"xltx",
"xm",
"xmind",
"xpi",
"xpm",
"xwd",
"xz",
"z",
"zip",
"zipx"
]

3
binary-extensions.json.d.ts vendored Normal file
View File

@@ -0,0 +1,3 @@
declare const binaryExtensionsJson: readonly string[];
export = binaryExtensionsJson;

1
browser-fallback.js Normal file
View File

@@ -0,0 +1 @@
export default typeof window !== 'undefined';

54
browser.js Normal file
View File

@@ -0,0 +1,54 @@
var BrowserslistError = require('./error')
function noop() {}
module.exports = {
loadQueries: function loadQueries() {
throw new BrowserslistError(
'Sharable configs are not supported in client-side build of Browserslist'
)
},
getStat: function getStat(opts) {
return opts.stats
},
loadConfig: function loadConfig(opts) {
if (opts.config) {
throw new BrowserslistError(
'Browserslist config are not supported in client-side build'
)
}
},
loadCountry: function loadCountry() {
throw new BrowserslistError(
'Country statistics are not supported ' +
'in client-side build of Browserslist'
)
},
loadFeature: function loadFeature() {
throw new BrowserslistError(
'Supports queries are not available in client-side build of Browserslist'
)
},
currentNode: function currentNode(resolve, context) {
return resolve(['maintained node versions'], context)[0]
},
parseConfig: noop,
readConfig: noop,
findConfig: noop,
findConfigFile: noop,
clearCaches: noop,
oldDataWarning: noop,
env: {}
}

16
browserslist Normal file
View File

@@ -0,0 +1,16 @@
#!/bin/sh
basedir=$(dirname "$(echo "$0" | sed -e 's,\\,/,g')")
case `uname` in
*CYGWIN*|*MINGW*|*MSYS*)
if command -v cygpath > /dev/null 2>&1; then
basedir=`cygpath -w "$basedir"`
fi
;;
esac
if [ -x "$basedir/node" ]; then
exec "$basedir/node" "$basedir/../browserslist/cli.js" "$@"
else
exec node "$basedir/../browserslist/cli.js" "$@"
fi

17
browserslist.cmd Normal file
View File

@@ -0,0 +1,17 @@
@ECHO off
GOTO start
:find_dp0
SET dp0=%~dp0
EXIT /b
:start
SETLOCAL
CALL :find_dp0
IF EXIST "%dp0%\node.exe" (
SET "_prog=%dp0%\node.exe"
) ELSE (
SET "_prog=node"
SET PATHEXT=%PATHEXT:;.JS;=;%
)
endLocal & goto #_undefined_# 2>NUL || title %COMSPEC% & "%_prog%" "%dp0%\..\browserslist\cli.js" %*

28
browserslist.ps1 Normal file
View File

@@ -0,0 +1,28 @@
#!/usr/bin/env pwsh
$basedir=Split-Path $MyInvocation.MyCommand.Definition -Parent
$exe=""
if ($PSVersionTable.PSVersion -lt "6.0" -or $IsWindows) {
# Fix case when both the Windows and Linux builds of Node
# are installed in the same directory
$exe=".exe"
}
$ret=0
if (Test-Path "$basedir/node$exe") {
# Support pipeline input
if ($MyInvocation.ExpectingInput) {
$input | & "$basedir/node$exe" "$basedir/../browserslist/cli.js" $args
} else {
& "$basedir/node$exe" "$basedir/../browserslist/cli.js" $args
}
$ret=$LASTEXITCODE
} else {
# Support pipeline input
if ($MyInvocation.ExpectingInput) {
$input | & "node$exe" "$basedir/../browserslist/cli.js" $args
} else {
& "node$exe" "$basedir/../browserslist/cli.js" $args
}
$ret=$LASTEXITCODE
}
exit $ret

167
changelog.md Normal file
View File

@@ -0,0 +1,167 @@
# [4.3.1](https://github.com/TehShrike/deepmerge/releases/tag/v4.3.1)
- Fix type definition for arrayMerge options. [#239](https://github.com/TehShrike/deepmerge/pull/239)
# [4.3.0](https://github.com/TehShrike/deepmerge/releases/tag/v4.3.0)
- Avoid thrown errors if the target doesn't have `propertyIsEnumerable`. [#252](https://github.com/TehShrike/deepmerge/pull/252)
# [4.2.2](https://github.com/TehShrike/deepmerge/releases/tag/v4.2.2)
- `isMergeableObject` is now only called if there are two values that could be merged. [a34dd4d2](https://github.com/TehShrike/deepmerge/commit/a34dd4d25bf5e250653540a2022bc832c7b00a19)
# [4.2.1](https://github.com/TehShrike/deepmerge/releases/tag/v4.2.1)
- Fix: falsey values can now be merged. [#170](https://github.com/TehShrike/deepmerge/issues/170)
# [4.2.0](https://github.com/TehShrike/deepmerge/releases/tag/v4.2.0)
- Properties are now only overwritten if they exist on the target object and are enumerable. [#164](https://github.com/TehShrike/deepmerge/pull/164)
Technically this could probably be a patch release since "which properties get overwritten" wasn't documented and accidentally overwriting a built-in function or some function up the property chain would almost certainly be undesirable, but it feels like a gray area, so here we are with a feature version bump.
# [4.1.2](https://github.com/TehShrike/deepmerge/releases/tag/v4.1.2)
- Rolled back #167 since `Object.assign` breaks ES5 support. [55067352](https://github.com/TehShrike/deepmerge/commit/55067352a92c65a6c44a5165f3387720aae1e192)
# [4.1.1](https://github.com/TehShrike/deepmerge/releases/tag/v4.1.1)
- The `options` argument is no longer mutated [#167](https://github.com/TehShrike/deepmerge/pull/167)
# [4.1.0](https://github.com/TehShrike/deepmerge/releases/tag/v4.1.0)
- `cloneUnlessOtherwiseSpecified` is now exposed to the `arrayMerge` function [#165](https://github.com/TehShrike/deepmerge/pull/165)
# [4.0.0](https://github.com/TehShrike/deepmerge/releases/tag/v4.0.0)
- The `main` entry point in `package.json` is now a CommonJS module instead of a UMD module [#155](https://github.com/TehShrike/deepmerge/pull/155)
# [3.3.0](https://github.com/TehShrike/deepmerge/releases/tag/v3.3.0)
- Enumerable Symbol properties are now copied [#151](https://github.com/TehShrike/deepmerge/pull/151)
# [3.2.1](https://github.com/TehShrike/deepmerge/releases/tag/v3.2.1)
- bumping dev dependency versions to try to shut up bogus security warnings from Github/npm [#149](https://github.com/TehShrike/deepmerge/pull/149)
# [3.2.0](https://github.com/TehShrike/deepmerge/releases/tag/v3.2.0)
- feature: added the [`customMerge`](https://github.com/TehShrike/deepmerge#custommerge) option [#133](https://github.com/TehShrike/deepmerge/pull/133)
# [3.1.0](https://github.com/TehShrike/deepmerge/releases/tag/v3.1.0)
- typescript typing: make the `all` function generic [#129](https://github.com/TehShrike/deepmerge/pull/129)
# [3.0.0](https://github.com/TehShrike/deepmerge/releases/tag/v3.0.0)
- drop ES module build [#123](https://github.com/TehShrike/deepmerge/issues/123)
# [2.2.1](https://github.com/TehShrike/deepmerge/releases/tag/v2.2.1)
- bug: typescript export type was wrong [#121](https://github.com/TehShrike/deepmerge/pull/121)
# [2.2.0](https://github.com/TehShrike/deepmerge/releases/tag/v2.2.0)
- feature: added TypeScript typings [#119](https://github.com/TehShrike/deepmerge/pull/119)
# [2.1.1](https://github.com/TehShrike/deepmerge/releases/tag/v2.1.1)
- documentation: Rename "methods" to "api", note ESM syntax [#103](https://github.com/TehShrike/deepmerge/pull/103)
- documentation: Fix grammar [#107](https://github.com/TehShrike/deepmerge/pull/107)
- documentation: Restructure headers for clarity + some wording tweaks [108](https://github.com/TehShrike/deepmerge/pull/108) + [109](https://github.com/TehShrike/deepmerge/pull/109)
# [2.1.0](https://github.com/TehShrike/deepmerge/releases/tag/v2.1.0)
- feature: Support a custom `isMergeableObject` function [#96](https://github.com/TehShrike/deepmerge/pull/96)
- documentation: note a Webpack bug that some users might need to work around [#100](https://github.com/TehShrike/deepmerge/pull/100)
# [2.0.1](https://github.com/TehShrike/deepmerge/releases/tag/v2.0.1)
- documentation: fix the old array merge algorithm in the readme. [#84](https://github.com/TehShrike/deepmerge/pull/84)
# [2.0.0](https://github.com/TehShrike/deepmerge/releases/tag/v2.0.0)
- breaking: the array merge algorithm has changed from a complicated thing to `target.concat(source).map(element => cloneUnlessOtherwiseSpecified(element, optionsArgument))`
- breaking: The `clone` option now defaults to `true`
- feature: `merge.all` now accepts an array of any size, even 0 or 1 elements
See [pull request 77](https://github.com/TehShrike/deepmerge/pull/77).
# [1.5.2](https://github.com/TehShrike/deepmerge/releases/tag/v1.5.2)
- fix: no longer attempts to merge React elements [#76](https://github.com/TehShrike/deepmerge/issues/76)
# [1.5.1](https://github.com/TehShrike/deepmerge/releases/tag/v1.5.1)
- bower support: officially dropping bower support. If you use bower, please depend on the [unpkg distribution](https://unpkg.com/deepmerge/dist/umd.js). See [#63](https://github.com/TehShrike/deepmerge/issues/63)
# [1.5.0](https://github.com/TehShrike/deepmerge/releases/tag/v1.5.0)
- bug fix: merging objects into arrays was allowed, and doesn't make any sense. [#65](https://github.com/TehShrike/deepmerge/issues/65) published as a feature release instead of a patch because it is a decent behavior change.
# [1.4.4](https://github.com/TehShrike/deepmerge/releases/tag/v1.4.4)
- bower support: updated `main` in bower.json
# [1.4.3](https://github.com/TehShrike/deepmerge/releases/tag/v1.4.3)
- bower support: inline is-mergeable-object in a new CommonJS build, so that people using both bower and CommonJS can bundle the library [0b34e6](https://github.com/TehShrike/deepmerge/commit/0b34e6e95f989f2fc8091d25f0d291c08f3d2d24)
# [1.4.2](https://github.com/TehShrike/deepmerge/releases/tag/v1.4.2)
- performance: bump is-mergeable-object dependency version for a slight performance improvement [5906c7](https://github.com/TehShrike/deepmerge/commit/5906c765d691d48e83d76efbb0d4b9ca150dc12c)
# [1.4.1](https://github.com/TehShrike/deepmerge/releases/tag/v1.4.1)
- documentation: fix unpkg link [acc45b](https://github.com/TehShrike/deepmerge/commit/acc45be85519c1df906a72ecb24764b622d18d47)
# [1.4.0](https://github.com/TehShrike/deepmerge/releases/tag/v1.4.0)
- api: instead of only exporting a UMD module, expose a UMD module with `pkg.main`, a CJS module with `pkg.browser`, and an ES module with `pkg.module` [#62](https://github.com/TehShrike/deepmerge/pull/62)
# [1.3.2](https://github.com/TehShrike/deepmerge/releases/tag/v1.3.2)
- documentation: note the minified/gzipped file sizes [56](https://github.com/TehShrike/deepmerge/pull/56)
- documentation: make data structures more readable in merge example: pull request [57](https://github.com/TehShrike/deepmerge/pull/57)
# [1.3.1](https://github.com/TehShrike/deepmerge/releases/tag/v1.3.1)
- documentation: clarify and test some array merging documentation: pull request [51](https://github.com/TehShrike/deepmerge/pull/51)
# [1.3.0](https://github.com/TehShrike/deepmerge/releases/tag/v1.3.0)
- feature: `merge.all`, a merge function that merges any number of objects: pull request [50](https://github.com/TehShrike/deepmerge/pull/50)
# [1.2.0](https://github.com/TehShrike/deepmerge/releases/tag/v1.2.0)
- fix: an error that would be thrown when an array would be merged onto a truthy non-array value: pull request [46](https://github.com/TehShrike/deepmerge/pull/46)
- feature: the ability to clone: Issue [28](https://github.com/TehShrike/deepmerge/issues/28), pull requests [44](https://github.com/TehShrike/deepmerge/pull/44) and [48](https://github.com/TehShrike/deepmerge/pull/48)
- maintenance: added tests + travis to `.npmignore`: pull request [47](https://github.com/TehShrike/deepmerge/pull/47)
# [1.1.1](https://github.com/TehShrike/deepmerge/releases/tag/v1.1.1)
- fix an issue where an error was thrown when merging an array onto a non-array: [Pull request 46](https://github.com/TehShrike/deepmerge/pull/46)
# [1.1.0](https://github.com/TehShrike/deepmerge/releases/tag/v1.1.0)
- allow consumers to specify their own array merging algorithm: [Pull request 37](https://github.com/TehShrike/deepmerge/pull/37)
# [1.0.3](https://github.com/TehShrike/deepmerge/releases/tag/v1.0.3)
- adding bower.json back: [Issue 38](https://github.com/TehShrike/deepmerge/pull/38)
- updating keywords and Github links in package.json [bc3898e](https://github.com/TehShrike/deepmerge/commit/bc3898e587a56f74591328f40f656b0152c1d5eb)
# [1.0.2](https://github.com/TehShrike/deepmerge/releases/tag/v1.0.2)
- Updating the readme: dropping bower, testing that the example works: [7102fc](https://github.com/TehShrike/deepmerge/commit/7102fcc4ddec11e2d33205866f9f18df14e5aeb5)
# [1.0.1](https://github.com/TehShrike/deepmerge/releases/tag/v1.0.1)
- `null`, dates, and regular expressions are now properly merged in arrays: [Issue 18](https://github.com/TehShrike/deepmerge/pull/18), plus commit: [ef1c6b](https://github.com/TehShrike/deepmerge/commit/ef1c6bac8350ba12a24966f0bc7da02560827586)
# 1.0.0
- Should only be a patch change, because this module is READY. [Issue 15](https://github.com/TehShrike/deepmerge/issues/15)
- Regular expressions are now treated like primitive values when merging: [Issue 30](https://github.com/TehShrike/deepmerge/pull/30)
- Dates are now treated like primitives when merging: [Issue 31](https://github.com/TehShrike/deepmerge/issues/31)

8
child_process.js Normal file
View File

@@ -0,0 +1,8 @@
require('thenify-all').withCallback(
require('child_process'),
exports, [
'exec',
'execFile',
]
)

84
chromium-versions.js Normal file
View File

@@ -0,0 +1,84 @@
module.exports = {
"39": "0.20",
"40": "0.21",
"41": "0.21",
"42": "0.25",
"43": "0.27",
"44": "0.30",
"45": "0.31",
"47": "0.36",
"49": "0.37",
"50": "1.1",
"51": "1.2",
"52": "1.3",
"53": "1.4",
"54": "1.4",
"56": "1.6",
"58": "1.7",
"59": "1.8",
"61": "2.0",
"66": "3.0",
"69": "4.0",
"72": "5.0",
"73": "5.0",
"76": "6.0",
"78": "7.0",
"79": "8.0",
"80": "8.0",
"82": "9.0",
"83": "9.0",
"84": "10.0",
"85": "10.0",
"86": "11.0",
"87": "11.0",
"89": "12.0",
"90": "13.0",
"91": "13.0",
"92": "14.0",
"93": "14.0",
"94": "15.0",
"95": "16.0",
"96": "16.0",
"98": "17.0",
"99": "18.0",
"100": "18.0",
"102": "19.0",
"103": "20.0",
"104": "20.0",
"105": "21.0",
"106": "21.0",
"107": "22.0",
"108": "22.0",
"110": "23.0",
"111": "24.0",
"112": "24.0",
"114": "25.0",
"116": "26.0",
"118": "27.0",
"119": "28.0",
"120": "28.0",
"121": "29.0",
"122": "29.0",
"123": "30.0",
"124": "30.0",
"125": "31.0",
"126": "31.0",
"127": "32.0",
"128": "32.0",
"129": "33.0",
"130": "33.0",
"131": "34.0",
"132": "34.0",
"133": "35.0",
"134": "35.0",
"135": "36.0",
"136": "36.0",
"137": "37.0",
"138": "37.0",
"139": "38.0",
"140": "38.0",
"141": "39.0",
"142": "39.0",
"143": "40.0",
"144": "40.0"
};

1
chromium-versions.json Normal file
View File

@@ -0,0 +1 @@
{"39":"0.20","40":"0.21","41":"0.21","42":"0.25","43":"0.27","44":"0.30","45":"0.31","47":"0.36","49":"0.37","50":"1.1","51":"1.2","52":"1.3","53":"1.4","54":"1.4","56":"1.6","58":"1.7","59":"1.8","61":"2.0","66":"3.0","69":"4.0","72":"5.0","73":"5.0","76":"6.0","78":"7.0","79":"8.0","80":"8.0","82":"9.0","83":"9.0","84":"10.0","85":"10.0","86":"11.0","87":"11.0","89":"12.0","90":"13.0","91":"13.0","92":"14.0","93":"14.0","94":"15.0","95":"16.0","96":"16.0","98":"17.0","99":"18.0","100":"18.0","102":"19.0","103":"20.0","104":"20.0","105":"21.0","106":"21.0","107":"22.0","108":"22.0","110":"23.0","111":"24.0","112":"24.0","114":"25.0","116":"26.0","118":"27.0","119":"28.0","120":"28.0","121":"29.0","122":"29.0","123":"30.0","124":"30.0","125":"31.0","126":"31.0","127":"32.0","128":"32.0","129":"33.0","130":"33.0","131":"34.0","132":"34.0","133":"35.0","134":"35.0","135":"36.0","136":"36.0","137":"37.0","138":"37.0","139":"38.0","140":"38.0","141":"39.0","142":"39.0","143":"40.0","144":"40.0"}

156
cli.js Normal file
View File

@@ -0,0 +1,156 @@
#!/usr/bin/env node
var fs = require('fs')
var updateDb = require('update-browserslist-db')
var browserslist = require('./')
var pkg = require('./package.json')
var args = process.argv.slice(2)
var USAGE =
'Usage:\n' +
' npx browserslist\n' +
' npx browserslist "QUERIES"\n' +
' npx browserslist --json "QUERIES"\n' +
' npx browserslist --config="path/to/browserlist/file"\n' +
' npx browserslist --coverage "QUERIES"\n' +
' npx browserslist --coverage=US "QUERIES"\n' +
' npx browserslist --coverage=US,RU,global "QUERIES"\n' +
' npx browserslist --env="environment name defined in config"\n' +
' npx browserslist --stats="path/to/browserlist/stats/file"\n' +
' npx browserslist --mobile-to-desktop\n' +
' npx browserslist --ignore-unknown-versions\n'
function isArg(arg) {
return args.some(function (str) {
return str === arg || str.indexOf(arg + '=') === 0
})
}
function error(msg) {
process.stderr.write('browserslist: ' + msg + '\n')
process.exit(1)
}
if (isArg('--help') || isArg('-h')) {
process.stdout.write(pkg.description + '.\n\n' + USAGE + '\n')
} else if (isArg('--version') || isArg('-v')) {
process.stdout.write('browserslist ' + pkg.version + '\n')
} else if (isArg('--update-db')) {
/* c8 ignore next 8 */
process.stdout.write(
'The --update-db command is deprecated.\n' +
'Please use npx update-browserslist-db@latest instead.\n'
)
process.stdout.write('Browserslist DB update will still be made.\n')
updateDb(function (str) {
process.stdout.write(str)
})
} else {
var mode = 'browsers'
var opts = {}
var queries
var areas
for (var i = 0; i < args.length; i++) {
if (args[i][0] !== '-') {
queries = args[i].replace(/^["']|["']$/g, '')
continue
}
var arg = args[i].split('=')
var name = arg[0]
var value = arg[1]
if (value) value = value.replace(/^["']|["']$/g, '')
if (name === '--config' || name === '-b') {
opts.config = value
} else if (name === '--env' || name === '-e') {
opts.env = value
} else if (name === '--stats' || name === '-s') {
opts.stats = value
} else if (name === '--coverage' || name === '-c') {
if (mode !== 'json') mode = 'coverage'
if (value) {
areas = value.split(',')
} else {
areas = ['global']
}
} else if (name === '--json') {
mode = 'json'
} else if (name === '--mobile-to-desktop') {
/* c8 ignore next */
opts.mobileToDesktop = true
} else if (name === '--ignore-unknown-versions') {
/* c8 ignore next */
opts.ignoreUnknownVersions = true
} else {
error('Unknown arguments ' + args[i] + '.\n\n' + USAGE)
}
}
var browsers
try {
browsers = browserslist(queries, opts)
} catch (e) {
if (e.name === 'BrowserslistError') {
error(e.message)
} /* c8 ignore start */ else {
throw e
} /* c8 ignore end */
}
var coverage
if (mode === 'browsers') {
browsers.forEach(function (browser) {
process.stdout.write(browser + '\n')
})
} else if (areas) {
coverage = areas.map(function (area) {
var stats
if (area !== 'global') {
stats = area
} else if (opts.stats) {
stats = JSON.parse(fs.readFileSync(opts.stats))
}
var result = browserslist.coverage(browsers, stats)
var round = Math.round(result * 100) / 100.0
return [area, round]
})
if (mode === 'coverage') {
var prefix = 'These browsers account for '
process.stdout.write(prefix)
coverage.forEach(function (data, index) {
var area = data[0]
var round = data[1]
var end = 'globally'
if (area && area !== 'global') {
end = 'in the ' + area.toUpperCase()
} else if (opts.stats) {
end = 'in custom statistics'
}
if (index !== 0) {
process.stdout.write(prefix.replace(/./g, ' '))
}
process.stdout.write(round + '% of all users ' + end + '\n')
})
}
}
if (mode === 'json') {
var data = { browsers: browsers }
if (coverage) {
data.coverage = coverage.reduce(function (object, j) {
object[j[0]] = j[1]
return object
}, {})
}
process.stdout.write(JSON.stringify(data, null, ' ') + '\n')
}
}

BIN
cliente.cpython-311.pyc Normal file

Binary file not shown.

64
cliente.py Normal file
View File

@@ -0,0 +1,64 @@
from pydantic import BaseModel, EmailStr, Field
from typing import Optional
from datetime import datetime
from app.models.enums import EstadoCliente
class ClienteBase(BaseModel):
nombre: str = Field(..., min_length=1, max_length=255)
email: EmailStr
rfc: Optional[str] = Field(None, max_length=13)
telefono: Optional[str] = Field(None, max_length=20)
permite_subclientes: bool = True
class ClienteCreate(ClienteBase):
limite_timbres: int = Field(0, ge=0)
class ClienteUpdate(BaseModel):
nombre: Optional[str] = Field(None, min_length=1, max_length=255)
email: Optional[EmailStr] = None
rfc: Optional[str] = Field(None, max_length=13)
telefono: Optional[str] = Field(None, max_length=20)
limite_timbres: Optional[int] = Field(None, ge=0)
estado: Optional[EstadoCliente] = None
permite_subclientes: Optional[bool] = None
class ClienteResponse(ClienteBase):
id: int
timbres_consumidos: int
estado: EstadoCliente
created_at: datetime
updated_at: Optional[datetime]
# Campos calculados dinámicamente
limite_timbres: Optional[int] = None
timbres_disponibles: Optional[int] = None
class Config:
from_attributes = True
class ClienteWithStats(ClienteResponse):
total_subclientes: int = 0
timbres_consumidos_subclientes: int = 0
total_limites_asignados: int = 0
class BalanceResponse(BaseModel):
cliente_id: int
nombre_cliente: str
limite_timbres: int
timbres_disponibles: int
timbres_consumidos: int
porcentaje_uso: float
total_subclientes: int = 0
timbres_consumidos_subclientes: int = 0
class RecargaTimbreCreate(BaseModel):
"""Schema específico para recargar timbres"""
cantidad: int = Field(..., gt=0)
descripcion: Optional[str] = Field(None, max_length=500)

BIN
clientes.cpython-311.pyc Normal file

Binary file not shown.

395
clientes.py Normal file
View File

@@ -0,0 +1,395 @@
from fastapi import APIRouter, Depends, HTTPException, status
from sqlalchemy.orm import Session
from typing import List
from app.database import get_db
from app.models import Cliente, SubCliente, MovimientoTimbre, LimiteTimbre, Usuario
from app.models.enums import TipoMovimiento, TipoLimite
from app.schemas import (
ClienteCreate, ClienteUpdate, ClienteResponse, ClienteWithStats,
BalanceResponse, RecargaTimbreCreate, MessageResponse, LimiteHistorialResponse, LimiteResponse
)
from app.dependencies import get_current_user
router = APIRouter()
@router.post("/", response_model=ClienteResponse, status_code=status.HTTP_201_CREATED)
def crear_cliente(
cliente: ClienteCreate,
db: Session = Depends(get_db),
current_user: Usuario = Depends(get_current_user)
):
"""
Crear un nuevo cliente con su límite de timbres inicial
"""
# Verificar si el email ya existe
if db.query(Cliente).filter(Cliente.email == cliente.email).first():
raise HTTPException(
status_code=status.HTTP_400_BAD_REQUEST,
detail="El email ya está registrado"
)
# Verificar si el RFC ya existe (si se proporciona)
if cliente.rfc and db.query(Cliente).filter(Cliente.rfc == cliente.rfc).first():
raise HTTPException(
status_code=status.HTTP_400_BAD_REQUEST,
detail="El RFC ya está registrado"
)
db_cliente = Cliente(
nombre=cliente.nombre,
email=cliente.email,
rfc=cliente.rfc,
telefono=cliente.telefono,
permite_subclientes=cliente.permite_subclientes
)
db.add(db_cliente)
db.flush() # Para obtener el ID sin hacer commit
# Crear el límite inicial si se proporciona
if cliente.limite_timbres > 0:
limite_inicial = LimiteTimbre(
cliente_id=db_cliente.id,
tipo=TipoLimite.ASIGNACION_INICIAL,
cantidad=cliente.limite_timbres,
descripcion="Límite inicial al crear el cliente"
)
db.add(limite_inicial)
db.commit()
db.refresh(db_cliente)
# Agregar campos calculados
response = ClienteResponse.model_validate(db_cliente)
response.limite_timbres = db_cliente.get_limite_actual(db)
response.timbres_disponibles = db_cliente.get_timbres_disponibles(db)
return response
@router.get("/", response_model=List[ClienteResponse])
def listar_clientes(
skip: int = 0,
limit: int = 100,
db: Session = Depends(get_db),
current_user: Usuario = Depends(get_current_user)
):
"""
Listar todos los clientes
"""
clientes = db.query(Cliente).offset(skip).limit(limit).all()
# Agregar campos calculados a cada cliente
response = []
for cliente in clientes:
cliente_dict = ClienteResponse.model_validate(cliente)
cliente_dict.limite_timbres = cliente.get_limite_actual(db)
cliente_dict.timbres_disponibles = cliente.get_timbres_disponibles(db)
response.append(cliente_dict)
return response
@router.get("/{cliente_id}", response_model=ClienteWithStats)
def obtener_cliente(
cliente_id: int,
db: Session = Depends(get_db),
current_user: Usuario = Depends(get_current_user)
):
"""
Obtener un cliente por ID con estadísticas de subclientes
"""
cliente = db.query(Cliente).filter(Cliente.id == cliente_id).first()
if not cliente:
raise HTTPException(
status_code=status.HTTP_404_NOT_FOUND,
detail="Cliente no encontrado"
)
# Obtener estadísticas de subclientes
total_subclientes = db.query(SubCliente).filter(
SubCliente.cliente_id == cliente_id
).count()
timbres_consumidos_subclientes = db.query(SubCliente).filter(
SubCliente.cliente_id == cliente_id
).with_entities(SubCliente.timbres_consumidos).all()
total_consumidos_sub = sum([t[0] for t in timbres_consumidos_subclientes])
# Obtener total de límites asignados
from sqlalchemy import func as sql_func
total_limites = db.query(sql_func.sum(LimiteTimbre.cantidad)).filter(
LimiteTimbre.cliente_id == cliente_id
).scalar() or 0
# Crear respuesta con estadísticas
response = ClienteWithStats.model_validate(cliente)
response.limite_timbres = cliente.get_limite_actual(db)
response.timbres_disponibles = cliente.get_timbres_disponibles(db)
response.total_subclientes = total_subclientes
response.timbres_consumidos_subclientes = total_consumidos_sub
response.total_limites_asignados = total_limites
return response
@router.put("/{cliente_id}", response_model=ClienteResponse)
def actualizar_cliente(
cliente_id: int,
cliente_update: ClienteUpdate,
db: Session = Depends(get_db),
current_user: Usuario = Depends(get_current_user)
):
"""
Actualizar información de un cliente
"""
db_cliente = db.query(Cliente).filter(Cliente.id == cliente_id).first()
if not db_cliente:
raise HTTPException(
status_code=status.HTTP_404_NOT_FOUND,
detail="Cliente no encontrado"
)
update_data = cliente_update.model_dump(exclude_unset=True)
# Verificar email único si se actualiza
if "email" in update_data and update_data["email"] != db_cliente.email:
if db.query(Cliente).filter(Cliente.email == update_data["email"]).first():
raise HTTPException(
status_code=status.HTTP_400_BAD_REQUEST,
detail="El email ya está registrado"
)
# Verificar RFC único si se actualiza
if "rfc" in update_data and update_data["rfc"] != db_cliente.rfc:
if db.query(Cliente).filter(Cliente.rfc == update_data["rfc"]).first():
raise HTTPException(
status_code=status.HTTP_400_BAD_REQUEST,
detail="El RFC ya está registrado"
)
# Actualizar campos básicos (excluyendo limite_timbres que ya no existe)
update_data_without_limite = {k: v for k, v in update_data.items() if k != 'limite_timbres'}
for field, value in update_data_without_limite.items():
setattr(db_cliente, field, value)
db.commit()
db.refresh(db_cliente)
# Preparar respuesta con campos calculados
response = ClienteResponse.model_validate(db_cliente)
response.limite_timbres = db_cliente.get_limite_actual(db)
response.timbres_disponibles = db_cliente.get_timbres_disponibles(db)
return response
@router.delete("/{cliente_id}", response_model=MessageResponse)
def eliminar_cliente(
cliente_id: int,
db: Session = Depends(get_db),
current_user: Usuario = Depends(get_current_user)
):
"""
Eliminar un cliente (también elimina sus subclientes y movimientos)
"""
db_cliente = db.query(Cliente).filter(Cliente.id == cliente_id).first()
if not db_cliente:
raise HTTPException(
status_code=status.HTTP_404_NOT_FOUND,
detail="Cliente no encontrado"
)
db.delete(db_cliente)
db.commit()
return {"message": f"Cliente {db_cliente.nombre} eliminado exitosamente"}
#==========================================================================================
@router.get("/{cliente_id}/balance", response_model=BalanceResponse)
def obtener_balance(
cliente_id: int,
db: Session = Depends(get_db),
current_user: Usuario = Depends(get_current_user)
):
"""
Obtener el balance de timbres de un cliente
"""
cliente = db.query(Cliente).filter(Cliente.id == cliente_id).first()
if not cliente:
raise HTTPException(
status_code=status.HTTP_404_NOT_FOUND,
detail="Cliente no encontrado"
)
total_subclientes = db.query(SubCliente).filter(
SubCliente.cliente_id == cliente_id
).count()
timbres_consumidos_subclientes = sum([
s.timbres_consumidos for s in db.query(SubCliente).filter(
SubCliente.cliente_id == cliente_id
).all()
])
limite_actual = cliente.get_limite_actual(db)
timbres_disponibles = cliente.get_timbres_disponibles(db)
porcentaje = (cliente.timbres_consumidos / limite_actual * 100) if limite_actual > 0 else 0
return {
"cliente_id": cliente.id,
"nombre_cliente": cliente.nombre,
"limite_timbres": limite_actual,
"timbres_disponibles": timbres_disponibles,
"timbres_consumidos": cliente.timbres_consumidos,
"porcentaje_uso": round(porcentaje, 2),
"total_subclientes": total_subclientes,
"timbres_consumidos_subclientes": timbres_consumidos_subclientes
}
#==========================================================================================
@router.post("/{cliente_id}/recargar", response_model=MessageResponse)
def recargar_timbres(
cliente_id: int,
recarga: RecargaTimbreCreate,
db: Session = Depends(get_db),
current_user: Usuario = Depends(get_current_user)
):
"""
Recargar timbres para un cliente (incrementa límite y disponibles)
"""
cliente = db.query(Cliente).filter(Cliente.id == cliente_id).first()
if not cliente:
raise HTTPException(
status_code=status.HTTP_404_NOT_FOUND,
detail="Cliente no encontrado"
)
# Crear nuevo límite (incremento)
nuevo_limite = LimiteTimbre(
cliente_id=cliente_id,
tipo=TipoLimite.INCREMENTO,
cantidad=recarga.cantidad,
descripcion=recarga.descripcion or f"Recarga de {recarga.cantidad} timbres"
)
db.add(nuevo_limite)
db.flush()
# Registrar movimiento de recarga
limite_actual = cliente.get_limite_actual(db)
timbres_disponibles = cliente.get_timbres_disponibles(db)
movimiento = MovimientoTimbre(
cliente_id=cliente_id,
tipo=TipoMovimiento.RECARGA,
cantidad=recarga.cantidad,
descripcion=recarga.descripcion,
balance_cliente=timbres_disponibles
)
db.add(movimiento)
db.commit()
return {
"message": f"Se recargaron {recarga.cantidad} timbres exitosamente",
"detail": {
"nuevo_limite": limite_actual,
"timbres_disponibles": timbres_disponibles
}
}
@router.get("/{cliente_id}/limites", response_model=LimiteHistorialResponse)
def obtener_historial_limites(
cliente_id: int,
db: Session = Depends(get_db),
current_user: Usuario = Depends(get_current_user)
):
"""
Obtener el historial completo de límites de un cliente
"""
cliente = db.query(Cliente).filter(Cliente.id == cliente_id).first()
if not cliente:
raise HTTPException(
status_code=status.HTTP_404_NOT_FOUND,
detail="Cliente no encontrado"
)
# Obtener todos los límites
limites = db.query(LimiteTimbre).filter(
LimiteTimbre.cliente_id == cliente_id
).order_by(LimiteTimbre.created_at.desc()).all()
# Calcular totales
from sqlalchemy import func as sql_func
limite_actual = db.query(sql_func.sum(LimiteTimbre.cantidad)).filter(
LimiteTimbre.cliente_id == cliente_id,
LimiteTimbre.activo == 1
).scalar() or 0
total_asignado = db.query(sql_func.sum(LimiteTimbre.cantidad)).filter(
LimiteTimbre.cliente_id == cliente_id
).scalar() or 0
return {
"limite_actual": limite_actual,
"total_asignado": total_asignado,
"historial": limites
}
@router.post("/{cliente_id}/ajustar-limite", response_model=MessageResponse)
def ajustar_limite(
cliente_id: int,
cantidad: int,
descripcion: str = None,
db: Session = Depends(get_db),
current_user: Usuario = Depends(get_current_user)
):
"""
Ajustar el límite de un cliente (puede ser positivo o negativo)
"""
cliente = db.query(Cliente).filter(Cliente.id == cliente_id).first()
if not cliente:
raise HTTPException(
status_code=status.HTTP_404_NOT_FOUND,
detail="Cliente no encontrado"
)
tipo = TipoLimite.INCREMENTO if cantidad > 0 else TipoLimite.DECREMENTO
nuevo_limite = LimiteTimbre(
cliente_id=cliente_id,
tipo=tipo,
cantidad=abs(cantidad),
descripcion=descripcion or f"Ajuste de límite: {cantidad}"
)
db.add(nuevo_limite)
db.commit()
limite_actual = cliente.get_limite_actual(db)
timbres_disponibles = cliente.get_timbres_disponibles(db)
return {
"message": "Límite ajustado exitosamente",
"detail": {
"ajuste": cantidad,
"nuevo_limite": limite_actual,
"timbres_disponibles": timbres_disponibles
}
}

6
clsx.d.mts Normal file
View File

@@ -0,0 +1,6 @@
export type ClassValue = ClassArray | ClassDictionary | string | number | bigint | null | boolean | undefined;
export type ClassDictionary = Record<string, any>;
export type ClassArray = ClassValue[];
export function clsx(...inputs: ClassValue[]): string;
export default clsx;

10
clsx.d.ts vendored Normal file
View File

@@ -0,0 +1,10 @@
declare namespace clsx {
type ClassValue = ClassArray | ClassDictionary | string | number | bigint | null | boolean | undefined;
type ClassDictionary = Record<string, any>;
type ClassArray = ClassValue[];
function clsx(...inputs: ClassValue[]): string;
}
declare function clsx(...inputs: clsx.ClassValue[]): string;
export = clsx;

24
commit-msg.sample Normal file
View File

@@ -0,0 +1,24 @@
#!/bin/sh
#
# An example hook script to check the commit log message.
# Called by "git commit" with one argument, the name of the file
# that has the commit message. The hook should exit with non-zero
# status after issuing an appropriate message if it wants to stop the
# commit. The hook is allowed to edit the commit message file.
#
# To enable this hook, rename this file to "commit-msg".
# Uncomment the below to add a Signed-off-by line to the message.
# Doing this in a hook is a bad idea in general, but the prepare-commit-msg
# hook is more suited to it.
#
# SOB=$(git var GIT_AUTHOR_IDENT | sed -n 's/^\(.*>\).*$/Signed-off-by: \1/p')
# grep -qs "^$SOB" "$1" || echo "$SOB" >> "$1"
# This example catches duplicate Signed-off-by lines.
test "" = "$(grep '^Signed-off-by: ' "$1" |
sort | uniq -c | sed -e '/^[ ]*1[ ]/d')" || {
echo >&2 Duplicate Signed-off-by lines.
exit 1
}

BIN
common.cpython-311.pyc Normal file

Binary file not shown.

7
common.py Normal file
View File

@@ -0,0 +1,7 @@
from pydantic import BaseModel
from typing import Optional
class MessageResponse(BaseModel):
message: str
detail: Optional[dict] = None

15
config Normal file
View File

@@ -0,0 +1,15 @@
[core]
repositoryformatversion = 0
filemode = false
bare = false
logallrefupdates = true
symlinks = false
ignorecase = true
[remote "origin"]
url = https://git.aduanasoft.com/ADUANASOFT/control_mve_frontend.git
fetch = +refs/heads/*:refs/remotes/origin/*
[branch "main"]
remote = origin
merge = refs/heads/main
vscode-merge-base = origin/main
gk-last-accessed = 2025-12-23T14:12:27.516Z

BIN
config.cpython-311.pyc Normal file

Binary file not shown.

30
config.py Normal file
View File

@@ -0,0 +1,30 @@
from pydantic_settings import BaseSettings
class Settings(BaseSettings):
# Database
POSTGRES_USER: str
POSTGRES_PASSWORD: str
POSTGRES_DB: str
POSTGRES_HOST: str
POSTGRES_PORT: int
# API
API_PORT: int = 8000
API_HOST: str = "0.0.0.0"
# Security
SECRET_KEY: str
ALGORITHM: str = "HS256"
ACCESS_TOKEN_EXPIRE_MINUTES: int = 30
@property
def DATABASE_URL(self) -> str:
return f"postgresql://{self.POSTGRES_USER}:{self.POSTGRES_PASSWORD}@{self.POSTGRES_HOST}:{self.POSTGRES_PORT}/{self.POSTGRES_DB}"
class Config:
env_file = ".env"
case_sensitive = True
settings = Settings()

162
core.json Normal file
View File

@@ -0,0 +1,162 @@
{
"assert": true,
"node:assert": [">= 14.18 && < 15", ">= 16"],
"assert/strict": ">= 15",
"node:assert/strict": ">= 16",
"async_hooks": ">= 8",
"node:async_hooks": [">= 14.18 && < 15", ">= 16"],
"buffer_ieee754": ">= 0.5 && < 0.9.7",
"buffer": true,
"node:buffer": [">= 14.18 && < 15", ">= 16"],
"child_process": true,
"node:child_process": [">= 14.18 && < 15", ">= 16"],
"cluster": ">= 0.5",
"node:cluster": [">= 14.18 && < 15", ">= 16"],
"console": true,
"node:console": [">= 14.18 && < 15", ">= 16"],
"constants": true,
"node:constants": [">= 14.18 && < 15", ">= 16"],
"crypto": true,
"node:crypto": [">= 14.18 && < 15", ">= 16"],
"_debug_agent": ">= 1 && < 8",
"_debugger": "< 8",
"dgram": true,
"node:dgram": [">= 14.18 && < 15", ">= 16"],
"diagnostics_channel": [">= 14.17 && < 15", ">= 15.1"],
"node:diagnostics_channel": [">= 14.18 && < 15", ">= 16"],
"dns": true,
"node:dns": [">= 14.18 && < 15", ">= 16"],
"dns/promises": ">= 15",
"node:dns/promises": ">= 16",
"domain": ">= 0.7.12",
"node:domain": [">= 14.18 && < 15", ">= 16"],
"events": true,
"node:events": [">= 14.18 && < 15", ">= 16"],
"freelist": "< 6",
"fs": true,
"node:fs": [">= 14.18 && < 15", ">= 16"],
"fs/promises": [">= 10 && < 10.1", ">= 14"],
"node:fs/promises": [">= 14.18 && < 15", ">= 16"],
"_http_agent": ">= 0.11.1",
"node:_http_agent": [">= 14.18 && < 15", ">= 16"],
"_http_client": ">= 0.11.1",
"node:_http_client": [">= 14.18 && < 15", ">= 16"],
"_http_common": ">= 0.11.1",
"node:_http_common": [">= 14.18 && < 15", ">= 16"],
"_http_incoming": ">= 0.11.1",
"node:_http_incoming": [">= 14.18 && < 15", ">= 16"],
"_http_outgoing": ">= 0.11.1",
"node:_http_outgoing": [">= 14.18 && < 15", ">= 16"],
"_http_server": ">= 0.11.1",
"node:_http_server": [">= 14.18 && < 15", ">= 16"],
"http": true,
"node:http": [">= 14.18 && < 15", ">= 16"],
"http2": ">= 8.8",
"node:http2": [">= 14.18 && < 15", ">= 16"],
"https": true,
"node:https": [">= 14.18 && < 15", ">= 16"],
"inspector": ">= 8",
"node:inspector": [">= 14.18 && < 15", ">= 16"],
"inspector/promises": [">= 19"],
"node:inspector/promises": [">= 19"],
"_linklist": "< 8",
"module": true,
"node:module": [">= 14.18 && < 15", ">= 16"],
"net": true,
"node:net": [">= 14.18 && < 15", ">= 16"],
"node-inspect/lib/_inspect": ">= 7.6 && < 12",
"node-inspect/lib/internal/inspect_client": ">= 7.6 && < 12",
"node-inspect/lib/internal/inspect_repl": ">= 7.6 && < 12",
"os": true,
"node:os": [">= 14.18 && < 15", ">= 16"],
"path": true,
"node:path": [">= 14.18 && < 15", ">= 16"],
"path/posix": ">= 15.3",
"node:path/posix": ">= 16",
"path/win32": ">= 15.3",
"node:path/win32": ">= 16",
"perf_hooks": ">= 8.5",
"node:perf_hooks": [">= 14.18 && < 15", ">= 16"],
"process": ">= 1",
"node:process": [">= 14.18 && < 15", ">= 16"],
"punycode": ">= 0.5",
"node:punycode": [">= 14.18 && < 15", ">= 16"],
"querystring": true,
"node:querystring": [">= 14.18 && < 15", ">= 16"],
"readline": true,
"node:readline": [">= 14.18 && < 15", ">= 16"],
"readline/promises": ">= 17",
"node:readline/promises": ">= 17",
"repl": true,
"node:repl": [">= 14.18 && < 15", ">= 16"],
"node:sea": [">= 20.12 && < 21", ">= 21.7"],
"smalloc": ">= 0.11.5 && < 3",
"node:sqlite": [">= 22.13 && < 23", ">= 23.4"],
"_stream_duplex": ">= 0.9.4",
"node:_stream_duplex": [">= 14.18 && < 15", ">= 16"],
"_stream_transform": ">= 0.9.4",
"node:_stream_transform": [">= 14.18 && < 15", ">= 16"],
"_stream_wrap": ">= 1.4.1",
"node:_stream_wrap": [">= 14.18 && < 15", ">= 16"],
"_stream_passthrough": ">= 0.9.4",
"node:_stream_passthrough": [">= 14.18 && < 15", ">= 16"],
"_stream_readable": ">= 0.9.4",
"node:_stream_readable": [">= 14.18 && < 15", ">= 16"],
"_stream_writable": ">= 0.9.4",
"node:_stream_writable": [">= 14.18 && < 15", ">= 16"],
"stream": true,
"node:stream": [">= 14.18 && < 15", ">= 16"],
"stream/consumers": ">= 16.7",
"node:stream/consumers": ">= 16.7",
"stream/promises": ">= 15",
"node:stream/promises": ">= 16",
"stream/web": ">= 16.5",
"node:stream/web": ">= 16.5",
"string_decoder": true,
"node:string_decoder": [">= 14.18 && < 15", ">= 16"],
"sys": [">= 0.4 && < 0.7", ">= 0.8"],
"node:sys": [">= 14.18 && < 15", ">= 16"],
"test/reporters": ">= 19.9 && < 20.2",
"node:test/reporters": [">= 18.17 && < 19", ">= 19.9", ">= 20"],
"test/mock_loader": ">= 22.3 && < 22.7",
"node:test/mock_loader": ">= 22.3 && < 22.7",
"node:test": [">= 16.17 && < 17", ">= 18"],
"timers": true,
"node:timers": [">= 14.18 && < 15", ">= 16"],
"timers/promises": ">= 15",
"node:timers/promises": ">= 16",
"_tls_common": ">= 0.11.13",
"node:_tls_common": [">= 14.18 && < 15", ">= 16"],
"_tls_legacy": ">= 0.11.3 && < 10",
"_tls_wrap": ">= 0.11.3",
"node:_tls_wrap": [">= 14.18 && < 15", ">= 16"],
"tls": true,
"node:tls": [">= 14.18 && < 15", ">= 16"],
"trace_events": ">= 10",
"node:trace_events": [">= 14.18 && < 15", ">= 16"],
"tty": true,
"node:tty": [">= 14.18 && < 15", ">= 16"],
"url": true,
"node:url": [">= 14.18 && < 15", ">= 16"],
"util": true,
"node:util": [">= 14.18 && < 15", ">= 16"],
"util/types": ">= 15.3",
"node:util/types": ">= 16",
"v8/tools/arguments": ">= 10 && < 12",
"v8/tools/codemap": [">= 4.4 && < 5", ">= 5.2 && < 12"],
"v8/tools/consarray": [">= 4.4 && < 5", ">= 5.2 && < 12"],
"v8/tools/csvparser": [">= 4.4 && < 5", ">= 5.2 && < 12"],
"v8/tools/logreader": [">= 4.4 && < 5", ">= 5.2 && < 12"],
"v8/tools/profile_view": [">= 4.4 && < 5", ">= 5.2 && < 12"],
"v8/tools/splaytree": [">= 4.4 && < 5", ">= 5.2 && < 12"],
"v8": ">= 1",
"node:v8": [">= 14.18 && < 15", ">= 16"],
"vm": true,
"node:vm": [">= 14.18 && < 15", ">= 16"],
"wasi": [">= 13.4 && < 13.5", ">= 18.17 && < 19", ">= 20"],
"node:wasi": [">= 18.17 && < 19", ">= 20"],
"worker_threads": ">= 11.7",
"node:worker_threads": [">= 14.18 && < 15", ">= 16"],
"zlib": ">= 0.5",
"node:zlib": [">= 14.18 && < 15", ">= 16"]
}

9
crypto.js Normal file
View File

@@ -0,0 +1,9 @@
require('thenify-all').withCallback(
require('crypto'),
exports, [
'pbkdf2',
'pseudoRandomBytes',
'randomBytes'
]
)

16
cssesc Normal file
View File

@@ -0,0 +1,16 @@
#!/bin/sh
basedir=$(dirname "$(echo "$0" | sed -e 's,\\,/,g')")
case `uname` in
*CYGWIN*|*MINGW*|*MSYS*)
if command -v cygpath > /dev/null 2>&1; then
basedir=`cygpath -w "$basedir"`
fi
;;
esac
if [ -x "$basedir/node" ]; then
exec "$basedir/node" "$basedir/../cssesc/bin/cssesc" "$@"
else
exec node "$basedir/../cssesc/bin/cssesc" "$@"
fi

17
cssesc.cmd Normal file
View File

@@ -0,0 +1,17 @@
@ECHO off
GOTO start
:find_dp0
SET dp0=%~dp0
EXIT /b
:start
SETLOCAL
CALL :find_dp0
IF EXIST "%dp0%\node.exe" (
SET "_prog=%dp0%\node.exe"
) ELSE (
SET "_prog=node"
SET PATHEXT=%PATHEXT:;.JS;=;%
)
endLocal & goto #_undefined_# 2>NUL || title %COMSPEC% & "%_prog%" "%dp0%\..\cssesc\bin\cssesc" %*

110
cssesc.js Normal file
View File

@@ -0,0 +1,110 @@
/*! https://mths.be/cssesc v3.0.0 by @mathias */
'use strict';
var object = {};
var hasOwnProperty = object.hasOwnProperty;
var merge = function merge(options, defaults) {
if (!options) {
return defaults;
}
var result = {};
for (var key in defaults) {
// `if (defaults.hasOwnProperty(key) { … }` is not needed here, since
// only recognized option names are used.
result[key] = hasOwnProperty.call(options, key) ? options[key] : defaults[key];
}
return result;
};
var regexAnySingleEscape = /[ -,\.\/:-@\[-\^`\{-~]/;
var regexSingleEscape = /[ -,\.\/:-@\[\]\^`\{-~]/;
var regexAlwaysEscape = /['"\\]/;
var regexExcessiveSpaces = /(^|\\+)?(\\[A-F0-9]{1,6})\x20(?![a-fA-F0-9\x20])/g;
// https://mathiasbynens.be/notes/css-escapes#css
var cssesc = function cssesc(string, options) {
options = merge(options, cssesc.options);
if (options.quotes != 'single' && options.quotes != 'double') {
options.quotes = 'single';
}
var quote = options.quotes == 'double' ? '"' : '\'';
var isIdentifier = options.isIdentifier;
var firstChar = string.charAt(0);
var output = '';
var counter = 0;
var length = string.length;
while (counter < length) {
var character = string.charAt(counter++);
var codePoint = character.charCodeAt();
var value = void 0;
// If its not a printable ASCII character…
if (codePoint < 0x20 || codePoint > 0x7E) {
if (codePoint >= 0xD800 && codePoint <= 0xDBFF && counter < length) {
// Its a high surrogate, and there is a next character.
var extra = string.charCodeAt(counter++);
if ((extra & 0xFC00) == 0xDC00) {
// next character is low surrogate
codePoint = ((codePoint & 0x3FF) << 10) + (extra & 0x3FF) + 0x10000;
} else {
// Its an unmatched surrogate; only append this code unit, in case
// the next code unit is the high surrogate of a surrogate pair.
counter--;
}
}
value = '\\' + codePoint.toString(16).toUpperCase() + ' ';
} else {
if (options.escapeEverything) {
if (regexAnySingleEscape.test(character)) {
value = '\\' + character;
} else {
value = '\\' + codePoint.toString(16).toUpperCase() + ' ';
}
} else if (/[\t\n\f\r\x0B]/.test(character)) {
value = '\\' + codePoint.toString(16).toUpperCase() + ' ';
} else if (character == '\\' || !isIdentifier && (character == '"' && quote == character || character == '\'' && quote == character) || isIdentifier && regexSingleEscape.test(character)) {
value = '\\' + character;
} else {
value = character;
}
}
output += value;
}
if (isIdentifier) {
if (/^-[-\d]/.test(output)) {
output = '\\-' + output.slice(1);
} else if (/\d/.test(firstChar)) {
output = '\\3' + firstChar + ' ' + output.slice(1);
}
}
// Remove spaces after `\HEX` escapes that are not followed by a hex digit,
// since theyre redundant. Note that this is only possible if the escape
// sequence isnt preceded by an odd number of backslashes.
output = output.replace(regexExcessiveSpaces, function ($0, $1, $2) {
if ($1 && $1.length % 2) {
// Its not safe to remove the space, so dont.
return $0;
}
// Strip the space.
return ($1 || '') + $2;
});
if (!isIdentifier && options.wrap) {
return quote + output + quote;
}
return output;
};
// Expose default options (so they can be overridden globally).
cssesc.options = {
'escapeEverything': false,
'isIdentifier': false,
'quotes': 'single',
'wrap': false
};
cssesc.version = '3.0.0';
module.exports = cssesc;

28
cssesc.ps1 Normal file
View File

@@ -0,0 +1,28 @@
#!/usr/bin/env pwsh
$basedir=Split-Path $MyInvocation.MyCommand.Definition -Parent
$exe=""
if ($PSVersionTable.PSVersion -lt "6.0" -or $IsWindows) {
# Fix case when both the Windows and Linux builds of Node
# are installed in the same directory
$exe=".exe"
}
$ret=0
if (Test-Path "$basedir/node$exe") {
# Support pipeline input
if ($MyInvocation.ExpectingInput) {
$input | & "$basedir/node$exe" "$basedir/../cssesc/bin/cssesc" $args
} else {
& "$basedir/node$exe" "$basedir/../cssesc/bin/cssesc" $args
}
$ret=$LASTEXITCODE
} else {
# Support pipeline input
if ($MyInvocation.ExpectingInput) {
$input | & "node$exe" "$basedir/../cssesc/bin/cssesc" $args
} else {
& "node$exe" "$basedir/../cssesc/bin/cssesc" $args
}
$ret=$LASTEXITCODE
}
exit $ret

BIN
database.cpython-311.pyc Normal file

Binary file not shown.

20
database.py Normal file
View File

@@ -0,0 +1,20 @@
from sqlalchemy import create_engine
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy.orm import sessionmaker
from app.config import settings
engine = create_engine(settings.DATABASE_URL)
SessionLocal = sessionmaker(autocommit=False, autoflush=False, bind=engine)
Base = declarative_base()
def get_db():
"""
Dependency para obtener la sesión de base de datos
"""
db = SessionLocal()
try:
yield db
finally:
db.close()

Binary file not shown.

59
dependencies.py Normal file
View File

@@ -0,0 +1,59 @@
from fastapi import Depends, HTTPException, status
from fastapi.security import HTTPBearer, HTTPAuthorizationCredentials
from sqlalchemy.orm import Session
from app.database import get_db
from app.models import Usuario
from app.auth import decode_access_token
security = HTTPBearer()
async def get_current_user(
credentials: HTTPAuthorizationCredentials = Depends(security),
db: Session = Depends(get_db)
) -> Usuario:
"""
Dependency para obtener el usuario actual desde el token JWT
"""
credentials_exception = HTTPException(
status_code=status.HTTP_401_UNAUTHORIZED,
detail="No se pudo validar las credenciales",
headers={"WWW-Authenticate": "Bearer"},
)
token = credentials.credentials
payload = decode_access_token(token)
if payload is None:
raise credentials_exception
username: str = payload.get("sub")
if username is None:
raise credentials_exception
user = db.query(Usuario).filter(Usuario.username == username).first()
if user is None:
raise credentials_exception
if not user.is_active:
raise HTTPException(
status_code=status.HTTP_403_FORBIDDEN,
detail="Usuario inactivo"
)
return user
async def get_current_active_superuser(
current_user: Usuario = Depends(get_current_user)
) -> Usuario:
"""
Dependency para verificar que el usuario sea superusuario
"""
if not current_user.is_superuser:
raise HTTPException(
status_code=status.HTTP_403_FORBIDDEN,
detail="No tiene permisos suficientes"
)
return current_user

1
description Normal file
View File

@@ -0,0 +1 @@
Unnamed repository; edit this file 'description' to name the repository.

2
dev-fallback.js Normal file
View File

@@ -0,0 +1,2 @@
const node_env = globalThis.process?.env?.NODE_ENV;
export default node_env && !node_env.toLowerCase().startsWith('prod');

274
didYouMean-1.2.1.js Normal file
View File

@@ -0,0 +1,274 @@
/*
didYouMean.js - A simple JavaScript matching engine
===================================================
[Available on GitHub](https://github.com/dcporter/didyoumean.js).
A super-simple, highly optimized JS library for matching human-quality input to a list of potential
matches. You can use it to suggest a misspelled command-line utility option to a user, or to offer
links to nearby valid URLs on your 404 page. (The examples below are taken from a personal project,
my [HTML5 business card](http://dcporter.aws.af.cm/me), which uses didYouMean.js to suggest correct
URLs from misspelled ones, such as [dcporter.aws.af.cm/me/instagarm](http://dcporter.aws.af.cm/me/instagarm).)
Uses the [Levenshtein distance algorithm](https://en.wikipedia.org/wiki/Levenshtein_distance).
didYouMean.js works in the browser as well as in node.js. To install it for use in node:
```
npm install didyoumean
```
Examples
--------
Matching against a list of strings:
```
var input = 'insargrm'
var list = ['facebook', 'twitter', 'instagram', 'linkedin'];
console.log(didYouMean(input, list));
> 'instagram'
// The method matches 'insargrm' to 'instagram'.
input = 'google plus';
console.log(didYouMean(input, list));
> null
// The method was unable to find 'google plus' in the list of options.
```
Matching against a list of objects:
```
var input = 'insargrm';
var list = [ { id: 'facebook' }, { id: 'twitter' }, { id: 'instagram' }, { id: 'linkedin' } ];
var key = 'id';
console.log(didYouMean(input, list, key));
> 'instagram'
// The method returns the matching value.
didYouMean.returnWinningObject = true;
console.log(didYouMean(input, list, key));
> { id: 'instagram' }
// The method returns the matching object.
```
didYouMean(str, list, [key])
----------------------------
- str: The string input to match.
- list: An array of strings or objects to match against.
- key (OPTIONAL): If your list array contains objects, you must specify the key which contains the string
to match against.
Returns: the closest matching string, or null if no strings exceed the threshold.
Options
-------
Options are set on the didYouMean function object. You may change them at any time.
### threshold
By default, the method will only return strings whose edit distance is less than 40% (0.4x) of their length.
For example, if a ten-letter string is five edits away from its nearest match, the method will return null.
You can control this by setting the "threshold" value on the didYouMean function. For example, to set the
edit distance threshold to 50% of the input string's length:
```
didYouMean.threshold = 0.5;
```
To return the nearest match no matter the threshold, set this value to null.
### thresholdAbsolute
This option behaves the same as threshold, but instead takes an integer number of edit steps. For example,
if thresholdAbsolute is set to 20 (the default), then the method will only return strings whose edit distance
is less than 20. Both options apply.
### caseSensitive
By default, the method will perform case-insensitive comparisons. If you wish to force case sensitivity, set
the "caseSensitive" value to true:
```
didYouMean.caseSensitive = true;
```
### nullResultValue
By default, the method will return null if there is no sufficiently close match. You can change this value here.
### returnWinningObject
By default, the method will return the winning string value (if any). If your list contains objects rather
than strings, you may set returnWinningObject to true.
```
didYouMean.returnWinningObject = true;
```
This option has no effect on lists of strings.
### returnFirstMatch
By default, the method will search all values and return the closest match. If you're simply looking for a "good-
enough" match, you can set your thresholds appropriately and set returnFirstMatch to true to substantially speed
things up.
License
-------
didYouMean copyright (c) 2013-2014 Dave Porter.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License
[here](http://www.apache.org/licenses/LICENSE-2.0).
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
(function() {
"use strict";
// The didYouMean method.
function didYouMean(str, list, key) {
if (!str) return null;
// If we're running a case-insensitive search, smallify str.
if (!didYouMean.caseSensitive) { str = str.toLowerCase(); }
// Calculate the initial value (the threshold) if present.
var thresholdRelative = didYouMean.threshold === null ? null : didYouMean.threshold * str.length,
thresholdAbsolute = didYouMean.thresholdAbsolute,
winningVal;
if (thresholdRelative !== null && thresholdAbsolute !== null) winningVal = Math.min(thresholdRelative, thresholdAbsolute);
else if (thresholdRelative !== null) winningVal = thresholdRelative;
else if (thresholdAbsolute !== null) winningVal = thresholdAbsolute;
else winningVal = null;
// Get the edit distance to each option. If the closest one is less than 40% (by default) of str's length,
// then return it.
var winner, candidate, testCandidate, val,
i, len = list.length;
for (i = 0; i < len; i++) {
// Get item.
candidate = list[i];
// If there's a key, get the candidate value out of the object.
if (key) { candidate = candidate[key]; }
// Gatekeep.
if (!candidate) { continue; }
// If we're running a case-insensitive search, smallify the candidate.
if (!didYouMean.caseSensitive) { testCandidate = candidate.toLowerCase(); }
else { testCandidate = candidate; }
// Get and compare edit distance.
val = getEditDistance(str, testCandidate, winningVal);
// If this value is smaller than our current winning value, OR if we have no winning val yet (i.e. the
// threshold option is set to null, meaning the caller wants a match back no matter how bad it is), then
// this is our new winner.
if (winningVal === null || val < winningVal) {
winningVal = val;
// Set the winner to either the value or its object, depending on the returnWinningObject option.
if (key && didYouMean.returnWinningObject) winner = list[i];
else winner = candidate;
// If we're returning the first match, return it now.
if (didYouMean.returnFirstMatch) return winner;
}
}
// If we have a winner, return it.
return winner || didYouMean.nullResultValue;
}
// Set default options.
didYouMean.threshold = 0.4;
didYouMean.thresholdAbsolute = 20;
didYouMean.caseSensitive = false;
didYouMean.nullResultValue = null;
didYouMean.returnWinningObject = null;
didYouMean.returnFirstMatch = false;
// Expose.
// In node...
if (typeof module !== 'undefined' && module.exports) {
module.exports = didYouMean;
}
// Otherwise...
else {
window.didYouMean = didYouMean;
}
var MAX_INT = Math.pow(2,32) - 1; // We could probably go higher than this, but for practical reasons let's not.
function getEditDistance(a, b, max) {
// Handle null or undefined max.
max = max || max === 0 ? max : MAX_INT;
var lena = a.length;
var lenb = b.length;
// Fast path - no A or B.
if (lena === 0) return Math.min(max + 1, lenb);
if (lenb === 0) return Math.min(max + 1, lena);
// Fast path - length diff larger than max.
if (Math.abs(lena - lenb) > max) return max + 1;
// Slow path.
var matrix = [],
i, j, colMin, minJ, maxJ;
// Set up the first row ([0, 1, 2, 3, etc]).
for (i = 0; i <= lenb; i++) { matrix[i] = [i]; }
// Set up the first column (same).
for (j = 0; j <= lena; j++) { matrix[0][j] = j; }
// Loop over the rest of the columns.
for (i = 1; i <= lenb; i++) {
colMin = MAX_INT;
minJ = 1;
if (i > max) minJ = i - max;
maxJ = lenb + 1;
if (maxJ > max + i) maxJ = max + i;
// Loop over the rest of the rows.
for (j = 1; j <= lena; j++) {
// If j is out of bounds, just put a large value in the slot.
if (j < minJ || j > maxJ) {
matrix[i][j] = max + 1;
}
// Otherwise do the normal Levenshtein thing.
else {
// If the characters are the same, there's no change in edit distance.
if (b.charAt(i - 1) === a.charAt(j - 1)) {
matrix[i][j] = matrix[i - 1][j - 1];
}
// Otherwise, see if we're substituting, inserting or deleting.
else {
matrix[i][j] = Math.min(matrix[i - 1][j - 1] + 1, // Substitute
Math.min(matrix[i][j - 1] + 1, // Insert
matrix[i - 1][j] + 1)); // Delete
}
}
// Either way, update colMin.
if (matrix[i][j] < colMin) colMin = matrix[i][j];
}
// If this column's minimum is greater than the allowed maximum, there's no point
// in going on with life.
if (colMin > max) return max + 1;
}
// If we made it this far without running into the max, then return the final matrix value.
return matrix[lenb][lena];
}
})();

17
didYouMean-1.2.1.min.js vendored Normal file
View File

@@ -0,0 +1,17 @@
/*
didYouMean.js copyright (c) 2013-2014 Dave Porter.
[Available on GitHub](https://github.com/dcporter/didyoumean.js).
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License
[here](http://www.apache.org/licenses/LICENSE-2.0).
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
(function(){"use strict";function e(t,r,i){if(!t)return null;if(!e.caseSensitive){t=t.toLowerCase()}var s=e.threshold===null?null:e.threshold*t.length,o=e.thresholdAbsolute,u;if(s!==null&&o!==null)u=Math.min(s,o);else if(s!==null)u=s;else if(o!==null)u=o;else u=null;var a,f,l,c,h,p=r.length;for(h=0;h<p;h++){f=r[h];if(i){f=f[i]}if(!f){continue}if(!e.caseSensitive){l=f.toLowerCase()}else{l=f}c=n(t,l,u);if(u===null||c<u){u=c;if(i&&e.returnWinningObject)a=r[h];else a=f;if(e.returnFirstMatch)return a}}return a||e.nullResultValue}function n(e,n,r){r=r||r===0?r:t;var i=e.length;var s=n.length;if(i===0)return Math.min(r+1,s);if(s===0)return Math.min(r+1,i);if(Math.abs(i-s)>r)return r+1;var o=[],u,a,f,l,c;for(u=0;u<=s;u++){o[u]=[u]}for(a=0;a<=i;a++){o[0][a]=a}for(u=1;u<=s;u++){f=t;l=1;if(u>r)l=u-r;c=s+1;if(c>r+u)c=r+u;for(a=1;a<=i;a++){if(a<l||a>c){o[u][a]=r+1}else{if(n.charAt(u-1)===e.charAt(a-1)){o[u][a]=o[u-1][a-1]}else{o[u][a]=Math.min(o[u-1][a-1]+1,Math.min(o[u][a-1]+1,o[u-1][a]+1))}}if(o[u][a]<f)f=o[u][a]}if(f>r)return r+1}return o[s][i]}e.threshold=.4;e.thresholdAbsolute=20;e.caseSensitive=false;e.nullResultValue=null;e.returnWinningObject=null;e.returnFirstMatch=false;if(typeof module!=="undefined"&&module.exports){module.exports=e}else{window.didYouMean=e}var t=Math.pow(2,32)-1})();

16
dns.js Normal file
View File

@@ -0,0 +1,16 @@
require('thenify-all').withCallback(
require('dns'),
exports, [
'lookup',
'resolve',
'resolve4',
'resolve6',
'resolveCname',
'resolveMx',
'resolveNs',
'resolveSrv',
'resolveTxt',
'reverse'
]
)

19
docker-compose.dev.yml Normal file
View File

@@ -0,0 +1,19 @@
services:
frontend:
image: node:20-alpine
working_dir: /app
container_name: contol-mve-frontend
ports:
- "5173:5173"
environment:
- VITE_API_BASE_URL=${VITE_API_URL}
volumes:
- ./:/app
- /app/node_modules
command: sh -c "npm install && npm run dev -- --host"
networks:
- control-mve-frontend-network
networks:
control-mve-frontend-network:
driver: bridge

14
docker-compose.prod.yaml Normal file
View File

@@ -0,0 +1,14 @@
services:
frontend:
build: .
ports: - "4000:80"
environment: - VITE_API_BASE_URL=${VITE_API_URL}
container_name: control-mve-frontend
restart: unless-stopped
networks:
- control-mve-frontend-network
networks:
control-mve-frontend-network:
driver: bridge

44
docker-compose.yml Normal file
View File

@@ -0,0 +1,44 @@
services:
db:
image: postgres:15-alpine
container_name: control_mve_postgres
environment:
POSTGRES_USER: ${POSTGRES_USER:-postgres}
POSTGRES_PASSWORD: ${POSTGRES_PASSWORD:-postgres}
POSTGRES_DB: ${POSTGRES_DB:-control_mve}
ports:
- "5432:5432"
volumes:
- postgres_data:/var/lib/postgresql/data
healthcheck:
test: ["CMD-SHELL", "pg_isready -U postgres"]
interval: 10s
timeout: 5s
retries: 5
networks:
- app-network
api:
build: .
container_name: control_mve_api
command: sh -c "sh /code/migrate.sh && uvicorn app.main:app --host 0.0.0.0 --port 8009 --reload"
volumes:
- ./app:/code/app
- ./alembic:/code/alembic
- ./alembic.ini:/code/alembic.ini
ports:
- "${API_PORT:-8009}:8009"
env_file:
- .env
depends_on:
db:
condition: service_healthy
networks:
- app-network
volumes:
postgres_data:
networks:
app-network:
driver: bridge

BIN
enums.cpython-311.pyc Normal file

Binary file not shown.

20
enums.py Normal file
View File

@@ -0,0 +1,20 @@
import enum
class EstadoCliente(str, enum.Enum):
ACTIVO = "activo"
INACTIVO = "inactivo"
SUSPENDIDO = "suspendido"
class TipoMovimiento(str, enum.Enum):
CONSUMO = "consumo"
RECARGA = "recarga"
AJUSTE = "ajuste"
class TipoLimite(str, enum.Enum):
ASIGNACION_INICIAL = "asignacion_inicial"
INCREMENTO = "incremento"
DECREMENTO = "decremento"
AJUSTE = "ajuste"

BIN
env.cpython-311.pyc Normal file

Binary file not shown.

89
env.py Normal file
View File

@@ -0,0 +1,89 @@
from logging.config import fileConfig
from sqlalchemy import engine_from_config
from sqlalchemy import pool
from alembic import context
# Importar la configuración de la app
import sys
import os
sys.path.insert(0, os.path.realpath(os.path.join(os.path.dirname(__file__), '..')))
from app.config import settings
from app.database import Base
# Importar todos los modelos para que Alembic los detecte
from app.models import Cliente, SubCliente, MovimientoTimbre, LimiteTimbre, Usuario
# this is the Alembic Config object, which provides
# access to the values within the .ini file in use.
config = context.config
# Interpret the config file for Python logging.
# This line sets up loggers basically.
if config.config_file_name is not None:
fileConfig(config.config_file_name)
# add your model's MetaData object here
# for 'autogenerate' support
target_metadata = Base.metadata
# other values from the config, defined by the needs of env.py,
# can be acquired:
# my_important_option = config.get_main_option("my_important_option")
# ... etc.
def run_migrations_offline() -> None:
"""Run migrations in 'offline' mode.
This configures the context with just a URL
and not an Engine, though an Engine is acceptable
here as well. By skipping the Engine creation
we don't even need a DBAPI to be available.
Calls to context.execute() here emit the given string to the
script output.
"""
url = settings.DATABASE_URL
context.configure(
url=url,
target_metadata=target_metadata,
literal_binds=True,
dialect_opts={"paramstyle": "named"},
)
with context.begin_transaction():
context.run_migrations()
def run_migrations_online() -> None:
"""Run migrations in 'online' mode.
In this scenario we need to create an Engine
and associate a connection with the context.
"""
configuration = config.get_section(config.config_ini_section)
configuration["sqlalchemy.url"] = settings.DATABASE_URL
connectable = engine_from_config(
configuration,
prefix="sqlalchemy.",
poolclass=pool.NullPool,
)
with connectable.connect() as connection:
context.configure(
connection=connection, target_metadata=target_metadata
)
with context.begin_transaction():
context.run_migrations()
if context.is_offline_mode():
run_migrations_offline()
else:
run_migrations_online()

7
error.d.ts vendored Normal file
View File

@@ -0,0 +1,7 @@
declare class BrowserslistError extends Error {
constructor(message: any)
name: 'BrowserslistError'
browserslist: true
}
export = BrowserslistError

12
error.js Normal file
View File

@@ -0,0 +1,12 @@
function BrowserslistError(message) {
this.name = 'BrowserslistError'
this.message = message
this.browserslist = true
if (Error.captureStackTrace) {
Error.captureStackTrace(this, BrowserslistError)
}
}
BrowserslistError.prototype = Error.prototype
module.exports = BrowserslistError

16
esbuild Normal file
View File

@@ -0,0 +1,16 @@
#!/bin/sh
basedir=$(dirname "$(echo "$0" | sed -e 's,\\,/,g')")
case `uname` in
*CYGWIN*|*MINGW*|*MSYS*)
if command -v cygpath > /dev/null 2>&1; then
basedir=`cygpath -w "$basedir"`
fi
;;
esac
if [ -x "$basedir/node" ]; then
exec "$basedir/node" "$basedir/../esbuild/bin/esbuild" "$@"
else
exec node "$basedir/../esbuild/bin/esbuild" "$@"
fi

17
esbuild.cmd Normal file
View File

@@ -0,0 +1,17 @@
@ECHO off
GOTO start
:find_dp0
SET dp0=%~dp0
EXIT /b
:start
SETLOCAL
CALL :find_dp0
IF EXIST "%dp0%\node.exe" (
SET "_prog=%dp0%\node.exe"
) ELSE (
SET "_prog=node"
SET PATHEXT=%PATHEXT:;.JS;=;%
)
endLocal & goto #_undefined_# 2>NUL || title %COMSPEC% & "%_prog%" "%dp0%\..\esbuild\bin\esbuild" %*

28
esbuild.ps1 Normal file
View File

@@ -0,0 +1,28 @@
#!/usr/bin/env pwsh
$basedir=Split-Path $MyInvocation.MyCommand.Definition -Parent
$exe=""
if ($PSVersionTable.PSVersion -lt "6.0" -or $IsWindows) {
# Fix case when both the Windows and Linux builds of Node
# are installed in the same directory
$exe=".exe"
}
$ret=0
if (Test-Path "$basedir/node$exe") {
# Support pipeline input
if ($MyInvocation.ExpectingInput) {
$input | & "$basedir/node$exe" "$basedir/../esbuild/bin/esbuild" $args
} else {
& "$basedir/node$exe" "$basedir/../esbuild/bin/esbuild" $args
}
$ret=$LASTEXITCODE
} else {
# Support pipeline input
if ($MyInvocation.ExpectingInput) {
$input | & "node$exe" "$basedir/../esbuild/bin/esbuild" $args
} else {
& "node$exe" "$basedir/../esbuild/bin/esbuild" $args
}
$ret=$LASTEXITCODE
}
exit $ret

14
example.js Normal file
View File

@@ -0,0 +1,14 @@
'use strict'
/* eslint-disable no-var */
var queue = require('./')(worker, 1)
queue.push(42, function (err, result) {
if (err) { throw err }
console.log('the result is', result)
})
function worker (arg, cb) {
cb(null, 42 * 2)
}

11
example.mjs Normal file
View File

@@ -0,0 +1,11 @@
import { promise as queueAsPromised } from './queue.js'
/* eslint-disable */
const queue = queueAsPromised(worker, 1)
console.log('the result is', await queue.push(42))
async function worker (arg) {
return 42 * 2
}

6
exclude Normal file
View File

@@ -0,0 +1,6 @@
# git ls-files --others --exclude-from=.git/info/exclude
# Lines that start with '#' are comments.
# For a project mostly in C, the following would be a good set of
# exclude patterns (uncomment them if you want to use them):
# *.[oa]
# *~

3
extensions.json Normal file
View File

@@ -0,0 +1,3 @@
{
"recommendations": ["svelte.svelte-vscode"]
}

1
false.js Normal file
View File

@@ -0,0 +1 @@
export default false;

79
fraction.d.mts Normal file
View File

@@ -0,0 +1,79 @@
/**
* Interface representing a fraction with numerator and denominator.
*/
export interface NumeratorDenominator {
n: number | bigint;
d: number | bigint;
}
/**
* Type for handling multiple types of input for Fraction operations.
*/
export type FractionInput =
| Fraction
| number
| bigint
| string
| [number | bigint | string, number | bigint | string]
| NumeratorDenominator;
/**
* Function signature for Fraction operations like add, sub, mul, etc.
*/
export type FractionParam = {
(numerator: number | bigint, denominator: number | bigint): Fraction;
(num: FractionInput): Fraction;
};
/**
* Fraction class representing a rational number with numerator and denominator.
*/
declare class Fraction {
constructor();
constructor(num: FractionInput);
constructor(numerator: number | bigint, denominator: number | bigint);
s: bigint;
n: bigint;
d: bigint;
abs(): Fraction;
neg(): Fraction;
add: FractionParam;
sub: FractionParam;
mul: FractionParam;
div: FractionParam;
pow: FractionParam;
log: FractionParam;
gcd: FractionParam;
lcm: FractionParam;
mod(): Fraction;
mod(num: FractionInput): Fraction;
ceil(places?: number): Fraction;
floor(places?: number): Fraction;
round(places?: number): Fraction;
roundTo: FractionParam;
inverse(): Fraction;
simplify(eps?: number): Fraction;
equals(num: FractionInput): boolean;
lt(num: FractionInput): boolean;
lte(num: FractionInput): boolean;
gt(num: FractionInput): boolean;
gte(num: FractionInput): boolean;
compare(num: FractionInput): number;
divisible(num: FractionInput): boolean;
valueOf(): number;
toString(decimalPlaces?: number): string;
toLatex(showMixed?: boolean): string;
toFraction(showMixed?: boolean): string;
toContinued(): bigint[];
clone(): Fraction;
}
export { Fraction as default, Fraction };

79
fraction.d.ts vendored Normal file
View File

@@ -0,0 +1,79 @@
declare class Fraction {
constructor();
constructor(num: Fraction.FractionInput);
constructor(numerator: number | bigint, denominator: number | bigint);
s: bigint;
n: bigint;
d: bigint;
abs(): Fraction;
neg(): Fraction;
add: Fraction.FractionParam;
sub: Fraction.FractionParam;
mul: Fraction.FractionParam;
div: Fraction.FractionParam;
pow: Fraction.FractionParam;
log: Fraction.FractionParam;
gcd: Fraction.FractionParam;
lcm: Fraction.FractionParam;
mod(): Fraction;
mod(num: Fraction.FractionInput): Fraction;
ceil(places?: number): Fraction;
floor(places?: number): Fraction;
round(places?: number): Fraction;
roundTo: Fraction.FractionParam;
inverse(): Fraction;
simplify(eps?: number): Fraction;
equals(num: Fraction.FractionInput): boolean;
lt(num: Fraction.FractionInput): boolean;
lte(num: Fraction.FractionInput): boolean;
gt(num: Fraction.FractionInput): boolean;
gte(num: Fraction.FractionInput): boolean;
compare(num: Fraction.FractionInput): number;
divisible(num: Fraction.FractionInput): boolean;
valueOf(): number;
toString(decimalPlaces?: number): string;
toLatex(showMixed?: boolean): string;
toFraction(showMixed?: boolean): string;
toContinued(): bigint[];
clone(): Fraction;
static default: typeof Fraction;
static Fraction: typeof Fraction;
}
declare namespace Fraction {
interface NumeratorDenominator { n: number | bigint; d: number | bigint; }
type FractionInput =
| Fraction
| number
| bigint
| string
| [number | bigint | string, number | bigint | string]
| NumeratorDenominator;
type FractionParam = {
(numerator: number | bigint, denominator: number | bigint): Fraction;
(num: FractionInput): Fraction;
};
}
/**
* Export matches CJS runtime:
* module.exports = Fraction;
* module.exports.default = Fraction;
* module.exports.Fraction = Fraction;
*/
declare const FractionExport: typeof Fraction & {
default: typeof Fraction;
Fraction: typeof Fraction;
};
export = FractionExport;

62
fs.js Normal file
View File

@@ -0,0 +1,62 @@
var Promise = require('any-promise')
var fs
try {
fs = require('graceful-fs')
} catch(err) {
fs = require('fs')
}
var api = [
'appendFile',
'chmod',
'chown',
'close',
'fchmod',
'fchown',
'fdatasync',
'fstat',
'fsync',
'ftruncate',
'futimes',
'lchown',
'link',
'lstat',
'mkdir',
'open',
'read',
'readFile',
'readdir',
'readlink',
'realpath',
'rename',
'rmdir',
'stat',
'symlink',
'truncate',
'unlink',
'utimes',
'write',
'writeFile'
]
typeof fs.access === 'function' && api.push('access')
typeof fs.copyFile === 'function' && api.push('copyFile')
typeof fs.mkdtemp === 'function' && api.push('mkdtemp')
require('thenify-all').withCallback(fs, exports, api)
exports.exists = function (filename, callback) {
// callback
if (typeof callback === 'function') {
return fs.stat(filename, function (err) {
callback(null, !err);
})
}
// or promise
return new Promise(function (resolve) {
fs.stat(filename, function (err) {
resolve(!err)
})
})
}

174
fsmonitor-watchman.sample Normal file
View File

@@ -0,0 +1,174 @@
#!/usr/bin/perl
use strict;
use warnings;
use IPC::Open2;
# An example hook script to integrate Watchman
# (https://facebook.github.io/watchman/) with git to speed up detecting
# new and modified files.
#
# The hook is passed a version (currently 2) and last update token
# formatted as a string and outputs to stdout a new update token and
# all files that have been modified since the update token. Paths must
# be relative to the root of the working tree and separated by a single NUL.
#
# To enable this hook, rename this file to "query-watchman" and set
# 'git config core.fsmonitor .git/hooks/query-watchman'
#
my ($version, $last_update_token) = @ARGV;
# Uncomment for debugging
# print STDERR "$0 $version $last_update_token\n";
# Check the hook interface version
if ($version ne 2) {
die "Unsupported query-fsmonitor hook version '$version'.\n" .
"Falling back to scanning...\n";
}
my $git_work_tree = get_working_dir();
my $retry = 1;
my $json_pkg;
eval {
require JSON::XS;
$json_pkg = "JSON::XS";
1;
} or do {
require JSON::PP;
$json_pkg = "JSON::PP";
};
launch_watchman();
sub launch_watchman {
my $o = watchman_query();
if (is_work_tree_watched($o)) {
output_result($o->{clock}, @{$o->{files}});
}
}
sub output_result {
my ($clockid, @files) = @_;
# Uncomment for debugging watchman output
# open (my $fh, ">", ".git/watchman-output.out");
# binmode $fh, ":utf8";
# print $fh "$clockid\n@files\n";
# close $fh;
binmode STDOUT, ":utf8";
print $clockid;
print "\0";
local $, = "\0";
print @files;
}
sub watchman_clock {
my $response = qx/watchman clock "$git_work_tree"/;
die "Failed to get clock id on '$git_work_tree'.\n" .
"Falling back to scanning...\n" if $? != 0;
return $json_pkg->new->utf8->decode($response);
}
sub watchman_query {
my $pid = open2(\*CHLD_OUT, \*CHLD_IN, 'watchman -j --no-pretty')
or die "open2() failed: $!\n" .
"Falling back to scanning...\n";
# In the query expression below we're asking for names of files that
# changed since $last_update_token but not from the .git folder.
#
# To accomplish this, we're using the "since" generator to use the
# recency index to select candidate nodes and "fields" to limit the
# output to file names only. Then we're using the "expression" term to
# further constrain the results.
my $last_update_line = "";
if (substr($last_update_token, 0, 1) eq "c") {
$last_update_token = "\"$last_update_token\"";
$last_update_line = qq[\n"since": $last_update_token,];
}
my $query = <<" END";
["query", "$git_work_tree", {$last_update_line
"fields": ["name"],
"expression": ["not", ["dirname", ".git"]]
}]
END
# Uncomment for debugging the watchman query
# open (my $fh, ">", ".git/watchman-query.json");
# print $fh $query;
# close $fh;
print CHLD_IN $query;
close CHLD_IN;
my $response = do {local $/; <CHLD_OUT>};
# Uncomment for debugging the watch response
# open ($fh, ">", ".git/watchman-response.json");
# print $fh $response;
# close $fh;
die "Watchman: command returned no output.\n" .
"Falling back to scanning...\n" if $response eq "";
die "Watchman: command returned invalid output: $response\n" .
"Falling back to scanning...\n" unless $response =~ /^\{/;
return $json_pkg->new->utf8->decode($response);
}
sub is_work_tree_watched {
my ($output) = @_;
my $error = $output->{error};
if ($retry > 0 and $error and $error =~ m/unable to resolve root .* directory (.*) is not watched/) {
$retry--;
my $response = qx/watchman watch "$git_work_tree"/;
die "Failed to make watchman watch '$git_work_tree'.\n" .
"Falling back to scanning...\n" if $? != 0;
$output = $json_pkg->new->utf8->decode($response);
$error = $output->{error};
die "Watchman: $error.\n" .
"Falling back to scanning...\n" if $error;
# Uncomment for debugging watchman output
# open (my $fh, ">", ".git/watchman-output.out");
# close $fh;
# Watchman will always return all files on the first query so
# return the fast "everything is dirty" flag to git and do the
# Watchman query just to get it over with now so we won't pay
# the cost in git to look up each individual file.
my $o = watchman_clock();
$error = $output->{error};
die "Watchman: $error.\n" .
"Falling back to scanning...\n" if $error;
output_result($o->{clock}, ("/"));
$last_update_token = $o->{clock};
eval { launch_watchman() };
return 0;
}
die "Watchman: $error.\n" .
"Falling back to scanning...\n" if $error;
return 1;
}
sub get_working_dir {
my $working_dir;
if ($^O =~ 'msys' || $^O =~ 'cygwin') {
$working_dir = Win32::GetCwd();
$working_dir =~ tr/\\/\//;
} else {
require Cwd;
$working_dir = Cwd::cwd();
}
return $working_dir;
}

2632
full-chromium-versions.js Normal file

File diff suppressed because it is too large Load Diff

File diff suppressed because one or more lines are too long

1684
full-versions.js Normal file

File diff suppressed because it is too large Load Diff

1
full-versions.json Normal file

File diff suppressed because one or more lines are too long

90
handler.d.ts vendored Normal file
View File

@@ -0,0 +1,90 @@
import type { WatchEventType, Stats, FSWatcher as NativeFsWatcher } from 'fs';
import type { FSWatcher, WatchHelper, Throttler } from './index.js';
import type { EntryInfo } from 'readdirp';
export type Path = string;
export declare const STR_DATA = "data";
export declare const STR_END = "end";
export declare const STR_CLOSE = "close";
export declare const EMPTY_FN: () => void;
export declare const IDENTITY_FN: (val: unknown) => unknown;
export declare const isWindows: boolean;
export declare const isMacos: boolean;
export declare const isLinux: boolean;
export declare const isFreeBSD: boolean;
export declare const isIBMi: boolean;
export declare const EVENTS: {
readonly ALL: "all";
readonly READY: "ready";
readonly ADD: "add";
readonly CHANGE: "change";
readonly ADD_DIR: "addDir";
readonly UNLINK: "unlink";
readonly UNLINK_DIR: "unlinkDir";
readonly RAW: "raw";
readonly ERROR: "error";
};
export type EventName = (typeof EVENTS)[keyof typeof EVENTS];
export type FsWatchContainer = {
listeners: (path: string) => void | Set<any>;
errHandlers: (err: unknown) => void | Set<any>;
rawEmitters: (ev: WatchEventType, path: string, opts: unknown) => void | Set<any>;
watcher: NativeFsWatcher;
watcherUnusable?: boolean;
};
export interface WatchHandlers {
listener: (path: string) => void;
errHandler: (err: unknown) => void;
rawEmitter: (ev: WatchEventType, path: string, opts: unknown) => void;
}
/**
* @mixin
*/
export declare class NodeFsHandler {
fsw: FSWatcher;
_boundHandleError: (error: unknown) => void;
constructor(fsW: FSWatcher);
/**
* Watch file for changes with fs_watchFile or fs_watch.
* @param path to file or dir
* @param listener on fs change
* @returns closer for the watcher instance
*/
_watchWithNodeFs(path: string, listener: (path: string, newStats?: any) => void | Promise<void>): (() => void) | undefined;
/**
* Watch a file and emit add event if warranted.
* @returns closer for the watcher instance
*/
_handleFile(file: Path, stats: Stats, initialAdd: boolean): (() => void) | undefined;
/**
* Handle symlinks encountered while reading a dir.
* @param entry returned by readdirp
* @param directory path of dir being read
* @param path of this item
* @param item basename of this item
* @returns true if no more processing is needed for this entry.
*/
_handleSymlink(entry: EntryInfo, directory: string, path: Path, item: string): Promise<boolean | undefined>;
_handleRead(directory: string, initialAdd: boolean, wh: WatchHelper, target: Path, dir: Path, depth: number, throttler: Throttler): Promise<unknown> | undefined;
/**
* Read directory to add / remove files from `@watched` list and re-read it on change.
* @param dir fs path
* @param stats
* @param initialAdd
* @param depth relative to user-supplied path
* @param target child path targeted for watch
* @param wh Common watch helpers for this path
* @param realpath
* @returns closer for the watcher instance.
*/
_handleDir(dir: string, stats: Stats, initialAdd: boolean, depth: number, target: string, wh: WatchHelper, realpath: string): Promise<(() => void) | undefined>;
/**
* Handle added file, directory, or glob pattern.
* Delegates call to _handleFile / _handleDir after checks.
* @param path to file or ir
* @param initialAdd was the file added at watch instantiation?
* @param priorWh depth relative to user-supplied path
* @param depth Child path actually targeted for watch
* @param target Child path actually targeted for watch
*/
_addToNodeFs(path: string, initialAdd: boolean, priorWh: WatchHelper | undefined, depth: number, target?: string): Promise<string | false | undefined>;
}

Some files were not shown because too many files have changed in this diff Show More