wexample-wex-addon-dev-javascript 8.1.5__py3-none-any.whl → 8.2.0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -24,6 +24,28 @@ class NpmRegistryGateway(AbstractGateway):
24
24
  if self.token:
25
25
  self.default_headers["Authorization"] = f"Bearer {self.token}"
26
26
 
27
+ def has_package(self, package: str) -> bool:
28
+ """Return True iff `package` is known to this registry, at any version.
29
+
30
+ A 404 means it was never published — the signal the first-publication
31
+ bootstrap reads. An unreachable registry raises instead of answering
32
+ False, so that a network glitch is never mistaken for a new package.
33
+ """
34
+ response = self.make_request(
35
+ endpoint=self._encode_package_name(package),
36
+ expected_status_codes=[200, 404],
37
+ fatal_if_unexpected=False,
38
+ quiet=True,
39
+ )
40
+ if response is None:
41
+ from wexample_helpers.error.gateway_error import GatewayError
42
+
43
+ raise GatewayError(
44
+ f"Registry {self.base_url} is unreachable: cannot tell whether "
45
+ f"{package} has ever been published."
46
+ )
47
+ return response.status_code == 200
48
+
27
49
  def has_version(self, package: str, version: str) -> bool:
28
50
  """Return True iff `package@version` is published on this registry.
29
51
 
@@ -32,9 +54,8 @@ class NpmRegistryGateway(AbstractGateway):
32
54
  registries that don't expose per-version URLs. Returns False on
33
55
  404 (unknown package or version not yet propagated).
34
56
  """
35
- encoded = package.replace("/", "%2F")
36
57
  response = self.make_request(
37
- endpoint=encoded,
58
+ endpoint=self._encode_package_name(package),
38
59
  expected_status_codes=[200, 404],
39
60
  fatal_if_unexpected=False,
40
61
  quiet=True,
@@ -42,3 +63,7 @@ class NpmRegistryGateway(AbstractGateway):
42
63
  if response is None or response.status_code != 200:
43
64
  return False
44
65
  return version in response.json().get("versions", {})
66
+
67
+ def _encode_package_name(self, package: str) -> str:
68
+ """A scoped name carries a slash, which the URL must not read as a path."""
69
+ return package.replace("/", "%2F")
@@ -0,0 +1,5 @@
1
+ """Npm registry defaults shared by the publication paths of this addon."""
2
+
3
+ from __future__ import annotations
4
+
5
+ NPM_REGISTRY_URL_DEFAULT = "https://registry.npmjs.org"
@@ -54,6 +54,14 @@ def node__service__install_local(
54
54
  # newer local source exists, so the deterministic wiring is a forced
55
55
  # symlink over node_modules/ — resolved by each package's declared scoped
56
56
  # name, which differs from its directory name.
57
+ #
58
+ # Only the javascript suite is linked here. The npm face of a PHP package
59
+ # (`@wexample/symfony-loader` → `vendor/wexample/symfony-loader/assets`) is
60
+ # not: the app's package.json must declare it as `link:` so that the
61
+ # `yarn install` above makes the symlink itself. Declared as `file:`, yarn
62
+ # copies it, and the copy is what TypeScript falls back to when a mapped
63
+ # file goes missing — see the symfony-design-system knowledge page
64
+ # contributing/assets-as-npm-package.
57
65
  script = f"""
58
66
  set -e
59
67
  cd {APP_DIR}
@@ -2,6 +2,7 @@ from __future__ import annotations
2
2
 
3
3
  from typing import TYPE_CHECKING
4
4
 
5
+ from wexample_helpers.classes.private_field import private_field
5
6
  from wexample_helpers.decorator.base_class import base_class
6
7
  from wexample_helpers.helper.string import string_to_kebab_case
7
8
  from wexample_helpers_git.helper.git import (
@@ -22,9 +23,18 @@ if TYPE_CHECKING:
22
23
  FrameworkPackageSuiteWorkdir,
23
24
  )
24
25
 
26
+ from wexample_wex_addon_dev_javascript.common.npm_registry_gateway import (
27
+ NpmRegistryGateway,
28
+ )
29
+
25
30
 
26
31
  @base_class
27
32
  class JavascriptPackageWorkdir(JavascriptWorkdir):
33
+ _first_publication: bool = private_field(
34
+ default=False,
35
+ description="Set when this run created the package on the registry",
36
+ )
37
+
28
38
  def get_package_dependency_name(self) -> str:
29
39
  return self.get_package_import_name()
30
40
 
@@ -131,9 +141,80 @@ class JavascriptPackageWorkdir(JavascriptWorkdir):
131
141
 
132
142
  return UPGRADE_TYPE_MAJOR
133
143
 
144
+ def _declare_trusted_publisher(self) -> None:
145
+ """Let the CI workflow publish the next versions, through `npm trust`.
146
+
147
+ The token npm keeps in ~/.npmrc is refused for account changes, so a
148
+ short-lived session is opened for this alone — in its own config, so
149
+ the everyday token is left untouched — and revoked right after. npm
150
+ asks the user to confirm both the login and the declaration through
151
+ links it prints, which any device can open.
152
+ """
153
+ import os
154
+ import shutil
155
+ import tempfile
156
+
157
+ from wexample_helpers.helper.user import user_get_real_gid, user_get_real_uid
158
+
159
+ repository, workflow = self._get_trusted_publisher_target()
160
+ config_dir = tempfile.mkdtemp(prefix="npm-trust-")
161
+ os.chown(config_dir, user_get_real_uid(), user_get_real_gid())
162
+ env = {"NPM_CONFIG_USERCONFIG": os.path.join(config_dir, ".npmrc")}
163
+
164
+ self.log("Declaring the CI as trusted publisher — confirm the two links npm prints.")
165
+ try:
166
+ self._shell_run_node_command(["npm", "login", "--auth-type=web"], env)
167
+ self._shell_run_node_command(
168
+ [
169
+ "npm",
170
+ "trust",
171
+ "github",
172
+ self.get_project_name(),
173
+ "--file",
174
+ workflow,
175
+ "--repo",
176
+ repository,
177
+ "--allow-publish",
178
+ "--yes",
179
+ ],
180
+ env,
181
+ )
182
+ finally:
183
+ try:
184
+ self._shell_run_node_command(["npm", "logout"], env)
185
+ except Exception:
186
+ pass
187
+ shutil.rmtree(config_dir, ignore_errors=True)
188
+
189
+ self.success(f"CI declared as trusted publisher of {self.get_project_name()}.")
190
+
134
191
  def _get_critical_directories(self) -> list[str]:
135
192
  return ["src"]
136
193
 
194
+ def _get_first_publication_notice(self) -> str:
195
+ """Why this first publication is slow, and what comes after it."""
196
+ return (
197
+ f"First publication of {self.get_project_name()}: npm usually needs "
198
+ "5 to 15 minutes to list a brand-new package.\n"
199
+ "Next versions publish from CI, which npm rejects until it is declared "
200
+ "as a trusted publisher. This is done right after the listing, and npm "
201
+ "will ask you to open two links to confirm: a login, then the "
202
+ "declaration itself."
203
+ )
204
+
205
+ def _get_manual_trusted_publisher_notice(self) -> str:
206
+ """The by-hand fallback when the declaration could not be scripted."""
207
+ repository, workflow = self._get_trusted_publisher_target()
208
+
209
+ return (
210
+ f"Could not declare the trusted publisher of {self.get_project_name()}; "
211
+ "its next version will fail to publish until it is done by hand:\n"
212
+ f" npmjs.com → {self.get_project_name()} → Settings → Trusted Publisher "
213
+ "→ GitHub Actions\n"
214
+ f" repository: {repository}\n"
215
+ f" workflow: {workflow}"
216
+ )
217
+
137
218
  def _get_readme_content(self) -> ReadmeContentConfigValue | None:
138
219
  from wexample_wex_addon_dev_javascript.config_value.javascript_package_readme_config_value import (
139
220
  JavascriptPackageReadmeContentConfigValue,
@@ -141,6 +222,25 @@ class JavascriptPackageWorkdir(JavascriptWorkdir):
141
222
 
142
223
  return JavascriptPackageReadmeContentConfigValue(workdir=self)
143
224
 
225
+ def _get_registry_gateway(self) -> NpmRegistryGateway:
226
+ """Gateway over the registry this package publishes to."""
227
+ from wexample_wex_addon_dev_javascript.common.npm_registry_gateway import (
228
+ NpmRegistryGateway,
229
+ )
230
+ from wexample_wex_addon_dev_javascript.const.registry import (
231
+ NPM_REGISTRY_URL_DEFAULT,
232
+ )
233
+
234
+ config = self.get_runtime_config()
235
+
236
+ return NpmRegistryGateway(
237
+ base_url=config.search("npm.registry_url").get_str_or_none()
238
+ or NPM_REGISTRY_URL_DEFAULT,
239
+ token=config.search("npm.api_token").get_str_or_none(),
240
+ io=self.io,
241
+ timeout=10,
242
+ )
243
+
144
244
  def _get_suite_workdir_class(self) -> type[FrameworkPackageSuiteWorkdir]:
145
245
  from wexample_wex_addon_dev_javascript.workdir.javascript_packages_suite_workdir import (
146
246
  JavascriptPackagesSuiteWorkdir,
@@ -148,10 +248,37 @@ class JavascriptPackageWorkdir(JavascriptWorkdir):
148
248
 
149
249
  return JavascriptPackagesSuiteWorkdir
150
250
 
251
+ def _get_trusted_publisher_target(self) -> tuple[str, str]:
252
+ """The `owner/repo` and workflow file npm must trust to publish."""
253
+ from urllib.parse import urlparse
254
+
255
+ url = self.get_app_config_file().read_parsed().get("repository") or ""
256
+ repository = urlparse(url.removeprefix("git+")).path.strip("/")
257
+
258
+ return repository.removesuffix(".git"), "publish.yml"
259
+
260
+ def _post_publish(self) -> None:
261
+ # After the registry wait on purpose: npm can only trust a package it
262
+ # already lists.
263
+ if not self._first_publication:
264
+ return
265
+ try:
266
+ self._declare_trusted_publisher()
267
+ except Exception:
268
+ self.warning(self._get_manual_trusted_publisher_notice())
269
+
151
270
  def _publish(self, force: bool = False) -> None:
152
271
  """Push a git tag to the deployment remote to trigger a CI/CD publication workflow."""
153
272
  from wexample_helpers_git.helper.git import git_push_tag
154
273
 
274
+ # Only public npm has the chicken-and-egg problem: a private registry
275
+ # (GitLab) lets its CI job token create the package itself.
276
+ if self.is_published_publicly() and not self._get_registry_gateway().has_package(
277
+ self.get_project_name()
278
+ ):
279
+ self._publish_first_version()
280
+ return
281
+
155
282
  remote = self._get_deployment_remote_name()
156
283
  if not remote:
157
284
  self.log("No deployment remote configured, skipping publication.")
@@ -167,11 +294,36 @@ class JavascriptPackageWorkdir(JavascriptWorkdir):
167
294
 
168
295
  git_push_tag(tag, cwd=cwd, remote=remote, inherit_stdio=True)
169
296
 
297
+ def _publish_first_version(self) -> None:
298
+ """Create the package on the registry from here, bypassing the CI workflow.
299
+
300
+ The workflow authenticates by OIDC alone (`id-token: write`, no token),
301
+ which npm only honours once the package has a trusted publisher — and
302
+ that is declared on a package settings page that does not exist until
303
+ the package does. So the very first version cannot come from CI, and
304
+ the CI tag is deliberately not pushed: it would start a run that can
305
+ only fail. Subsequent versions take the normal tag path again.
306
+ """
307
+ manager = self._get_package_manager()
308
+ package = self.get_project_name()
309
+
310
+ self.log(
311
+ f"{package} is not on the registry yet: publishing this first "
312
+ "version locally, the workflow cannot create it."
313
+ )
314
+
315
+ # Same two steps as the workflow: publishing runs prepublishOnly,
316
+ # which type-checks against dependencies that must be installed.
317
+ self._shell_run_node_command([manager, "install"])
318
+ self._shell_run_node_command([manager, "publish", "--access", "public"])
319
+
320
+ self._first_publication = True
321
+ self.success(f"{package} now exists on the registry.")
322
+ self.warning(self._get_first_publication_notice())
323
+
170
324
  def _refresh_lockfile(self) -> None:
171
325
  import shutil
172
326
 
173
- from wexample_helpers.helper.shell import shell_run
174
-
175
327
  for lockfile, command in self._LOCKFILE_REFRESH_COMMANDS.items():
176
328
  if not (self.get_path() / lockfile).exists():
177
329
  continue
@@ -182,7 +334,7 @@ class JavascriptPackageWorkdir(JavascriptWorkdir):
182
334
  f"available on this machine. A stale lockfile would break "
183
335
  f"the strict CI install."
184
336
  )
185
- shell_run(command, cwd=self.get_path())
337
+ self._shell_run_node_command(command)
186
338
  return
187
339
 
188
340
  def _wait_for_registry(self) -> None:
@@ -196,25 +348,9 @@ class JavascriptPackageWorkdir(JavascriptWorkdir):
196
348
  PollingCallbackManager,
197
349
  )
198
350
 
199
- from wexample_wex_addon_dev_javascript.common.npm_registry_gateway import (
200
- NpmRegistryGateway,
201
- )
202
-
203
351
  package = self.get_project_name()
204
352
  version = self.get_setup_version()
205
-
206
- registry_base = (
207
- self.get_runtime_config().search("npm.registry_url").get_str_or_none()
208
- or "https://registry.npmjs.org"
209
- )
210
- token = self.get_runtime_config().search("npm.api_token").get_str_or_none()
211
-
212
- gateway = NpmRegistryGateway(
213
- base_url=registry_base,
214
- token=token,
215
- io=self.io,
216
- timeout=10,
217
- )
353
+ gateway = self._get_registry_gateway()
218
354
 
219
355
  max_attempts = 40
220
356
  delay_seconds = 30
@@ -222,9 +358,16 @@ class JavascriptPackageWorkdir(JavascriptWorkdir):
222
358
  self.log(f"Waiting for {package}@{version} to appear on registry…")
223
359
 
224
360
  def on_retry(attempt, max_a, delay, _exc, _msg) -> None:
225
- self.log(
226
- f"Not yet available (attempt {attempt}/{max_a}), retrying in {delay}s…"
227
- )
361
+ if not self._first_publication:
362
+ self.log(
363
+ f"Not yet available (attempt {attempt}/{max_a}), retrying in {delay}s…"
364
+ )
365
+ # A first listing is expected to be slow and was announced as
366
+ # such: one line every two minutes is enough to show it is alive.
367
+ elif attempt % 4 == 0:
368
+ self.log(
369
+ f"npm is still listing {package} ({attempt * delay // 60} min)…"
370
+ )
228
371
 
229
372
  PollingCallbackManager(
230
373
  callback=lambda: True if gateway.has_version(package, version) else None,
@@ -238,3 +381,4 @@ class JavascriptPackageWorkdir(JavascriptWorkdir):
238
381
  ).run()
239
382
 
240
383
  self.success(f"{package}@{version} is available.")
384
+
@@ -24,6 +24,21 @@ if TYPE_CHECKING:
24
24
 
25
25
  @base_class
26
26
  class JavascriptWorkdir(WithAiWorkdirMixin, CodeBaseWorkdir):
27
+ # What a test file looks like, whatever the runner the package picked.
28
+ _TEST_FILE_SUFFIXES: tuple[str, ...] = tuple(
29
+ f".{kind}.{extension}"
30
+ for kind in ("test", "spec")
31
+ for extension in ("js", "jsx", "mjs", "cjs", "ts", "tsx", "mts", "cts")
32
+ )
33
+ # Lockfile → the package manager that wrote it. Order matters: a repo
34
+ # carrying several lockfiles is read as the first one listed, exactly as
35
+ # JavascriptPackageWorkdir._LOCKFILE_REFRESH_COMMANDS does.
36
+ _LOCKFILE_PACKAGE_MANAGERS: dict[str, str] = {
37
+ "package-lock.json": "npm",
38
+ "pnpm-lock.yaml": "pnpm",
39
+ "yarn.lock": "yarn",
40
+ }
41
+
27
42
  def get_app_config_file(self, reload: bool = True) -> JavascriptPackageJsonFile:
28
43
  from wexample_wex_addon_dev_javascript.file.javascript_package_json_file import (
29
44
  JavascriptPackageJsonFile,
@@ -51,6 +66,17 @@ class JavascriptWorkdir(WithAiWorkdirMixin, CodeBaseWorkdir):
51
66
 
52
67
  return options
53
68
 
69
+ def has_tests(self) -> bool:
70
+ # The tests/ directory itself is filestate-managed scaffolding and
71
+ # exists for every JavaScript package; only actual test files count.
72
+ tests_path = self.get_path() / "tests"
73
+ if not tests_path.is_dir():
74
+ return False
75
+ return any(
76
+ path.name.endswith(self._TEST_FILE_SUFFIXES)
77
+ for path in tests_path.rglob("*")
78
+ )
79
+
54
80
  def prepare_value(self, raw_value: DictConfig | None = None) -> DictConfig:
55
81
  from wexample_filestate.const.disk import DiskItemType
56
82
 
@@ -124,6 +150,32 @@ class JavascriptWorkdir(WithAiWorkdirMixin, CodeBaseWorkdir):
124
150
 
125
151
  return raw_value
126
152
 
153
+ def test_run(self, format: str | None = None) -> None:
154
+ """Run the package's own `test` script; raise on failure.
155
+
156
+ A JavaScript package names its runner itself — vitest, jest, plain
157
+ node — so the script declared in package.json is the only portable
158
+ entry point. `format` is ignored: unlike pytest-cov, nothing here
159
+ produces a coverage report to shape.
160
+ """
161
+ manager = self._get_package_manager()
162
+ scripts = self.get_app_config_file().read_parsed().get("scripts", {})
163
+
164
+ if "test" not in scripts:
165
+ raise NotImplementedError(
166
+ f"{self.get_project_name()} ships test files under tests/ but its "
167
+ "package.json declares no `test` script; add one so they can run."
168
+ )
169
+
170
+ # Tests import the dependencies, which the publication flow never
171
+ # installs on its own — a fresh clone would fail on the first import
172
+ # rather than on a real assertion.
173
+ if not any(self.get_path().glob("node_modules/*")):
174
+ self.log(f"Installing {self.get_project_name()} dependencies before tests…")
175
+ self._shell_run_node_command([manager, "install"])
176
+
177
+ self._shell_run_node_command([manager, "run", "test"])
178
+
127
179
  def _canonicalize_dep_name(self, name: str) -> str:
128
180
  return name
129
181
 
@@ -150,3 +202,46 @@ class JavascriptWorkdir(WithAiWorkdirMixin, CodeBaseWorkdir):
150
202
 
151
203
  def _default_dependency_operator(self) -> str:
152
204
  return "^"
205
+
206
+ def _get_node_command_environment(self) -> dict[str, str]:
207
+ """Environment a node command needs to be the invoking user's own."""
208
+ import os
209
+
210
+ from wexample_helpers.helper.user import user_get_real_home, user_get_real_path
211
+
212
+ # Under sudo HOME still points at /root: npm would read root's .npmrc
213
+ # (no registry token) and root's cache, which the lifecycle scripts —
214
+ # dropped back to the invoking uid by npm — then cannot even write.
215
+ # PATH is sudo's secure_path: the distribution's node, not nvm's.
216
+ return {
217
+ **os.environ,
218
+ "HOME": user_get_real_home(),
219
+ "PATH": user_get_real_path(),
220
+ }
221
+
222
+ def _get_package_manager(self) -> str:
223
+ """The package manager this repository uses, told by its lockfile."""
224
+ for lockfile, manager in self._LOCKFILE_PACKAGE_MANAGERS.items():
225
+ if (self.get_path() / lockfile).exists():
226
+ return manager
227
+ return "npm"
228
+
229
+ def _shell_run_node_command(
230
+ self, cmd: list[str], extra_env: dict[str, str] | None = None
231
+ ) -> None:
232
+ """Run a node toolchain command as the user who invoked wex.
233
+
234
+ Publication carries @as_sudo, so the process is root by the time it
235
+ reaches here: npm run as root would use root's node, token and cache.
236
+ Earlier release steps ran as root too, so whatever they wrote in the
237
+ workdir (package.json, lockfile…) is handed back first — npm could not
238
+ rewrite it otherwise.
239
+ """
240
+ from wexample_helpers.helper.shell import shell_run
241
+ from wexample_helpers.helper.user import user_run_as_real_user
242
+
243
+ self.restore_real_user_ownership()
244
+ env = {**self._get_node_command_environment(), **(extra_env or {})}
245
+
246
+ with user_run_as_real_user():
247
+ shell_run(cmd, cwd=self.get_path(), env=env, inherit_stdio=True)
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: wexample-wex-addon-dev-javascript
3
- Version: 8.1.5
3
+ Version: 8.2.0
4
4
  Summary: Extends wex with JavaScript support: enforces JS/TS project layout and symlinks local npm packages into node_modules
5
5
  Author-Email: weeger <contact@wexample.com>
6
6
  License: MIT
@@ -13,8 +13,8 @@ Requires-Dist: attrs>=23.1.0
13
13
  Requires-Dist: cattrs>=23.1.0
14
14
  Requires-Dist: wexample-api>=6.8.0
15
15
  Requires-Dist: wexample-filestate-javascript>=6.6.0
16
- Requires-Dist: wexample-wex-addon-ai>=15.0.0
17
- Requires-Dist: wexample-wex-addon-app>=31.0.0
16
+ Requires-Dist: wexample-wex-addon-ai>=16.0.0
17
+ Requires-Dist: wexample-wex-addon-app>=32.0.0
18
18
  Provides-Extra: dev
19
19
  Requires-Dist: pytest; extra == "dev"
20
20
  Requires-Dist: pytest-cov; extra == "dev"
@@ -22,7 +22,7 @@ Description-Content-Type: text/markdown
22
22
 
23
23
  # wex_addon_dev_javascript
24
24
 
25
- Version: 8.1.5
25
+ Version: 8.2.0
26
26
 
27
27
  `wex-addon-dev-javascript` extends wex for JavaScript and TypeScript developers: it enforces a standard project layout — requiring `package.json`, `tsconfig.json`, `.npmrc`, `src/`, `tests/`, and the corresponding `.gitignore` rules — and in local environments symlinks locally-developed npm packages directly into a running container's `node_modules/` so monorepo packages resolve without a registry publish cycle. It also contributes a `node` service and a `vite` service, each backed by Docker Compose, where the vite service patches `allowedHosts` in `vite.config.ts` for reverse-proxy use and the node service handles lockfile refresh, annotated-tag release, and registry polling for npm package suites managed through wex.
28
28
 
@@ -251,8 +251,8 @@ Visit the [Wexample Suite documentation](https://docs.wexample.com) for the comp
251
251
  - cattrs: >=23.1.0
252
252
  - wexample-api: >=6.8.0
253
253
  - wexample-filestate-javascript: >=6.6.0
254
- - wexample-wex-addon-ai: >=15.0.0
255
- - wexample-wex-addon-app: >=31.0.0
254
+ - wexample-wex-addon-ai: >=16.0.0
255
+ - wexample-wex-addon-app: >=32.0.0
256
256
 
257
257
  ## Versioning & Compatibility Policy
258
258
 
@@ -1,13 +1,14 @@
1
- wexample_wex_addon_dev_javascript-8.1.5.dist-info/METADATA,sha256=IrwC5f4cMAgzWyNd5egcVYCm1z-0LjneRJeDK7OrhxI,18012
2
- wexample_wex_addon_dev_javascript-8.1.5.dist-info/WHEEL,sha256=VP-D4TPS230sME9Z3vb3INXvo1yt0924YRm5AOsk_dE,90
3
- wexample_wex_addon_dev_javascript-8.1.5.dist-info/entry_points.txt,sha256=WwYdg3RL2Ey1fg4JNNkcQxZcQRgZSgPLLzSDi6lbYgI,143
1
+ wexample_wex_addon_dev_javascript-8.2.0.dist-info/METADATA,sha256=jQSdi-wtyOIrG76xCCSSOrMF4_UTHmj0i24IjqRQpj8,18012
2
+ wexample_wex_addon_dev_javascript-8.2.0.dist-info/WHEEL,sha256=Y8xFLOH-FrS4gLE6ON4ti06sl2W_9QUDiRaTK3tfwig,91
3
+ wexample_wex_addon_dev_javascript-8.2.0.dist-info/entry_points.txt,sha256=WwYdg3RL2Ey1fg4JNNkcQxZcQRgZSgPLLzSDi6lbYgI,143
4
4
  wexample_wex_addon_dev_javascript/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
5
5
  wexample_wex_addon_dev_javascript/__pycache__/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
6
6
  wexample_wex_addon_dev_javascript/common/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
7
- wexample_wex_addon_dev_javascript/common/npm_registry_gateway.py,sha256=fdmsO6DZVvAQw1o3QmtjLBq0Dr1i_EAfnKvxQx5VdIw,1657
7
+ wexample_wex_addon_dev_javascript/common/npm_registry_gateway.py,sha256=jcAIOZN1eiPeRSjradY095VI93ne86ijbVAZcXzCKpQ,2742
8
8
  wexample_wex_addon_dev_javascript/config_value/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
9
9
  wexample_wex_addon_dev_javascript/config_value/javascript_package_readme_config_value.py,sha256=FaYjL6A6Zv8sYnz4cWqD4DsrNO9EMYvSi1-8GCbmNvs,522
10
10
  wexample_wex_addon_dev_javascript/const/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
11
+ wexample_wex_addon_dev_javascript/const/registry.py,sha256=pkGypHvxhPeb6-Quyv8Vodt8LIBmbPYHV7ibL1TemSw,168
11
12
  wexample_wex_addon_dev_javascript/const/tags.py,sha256=qirMGuj7UqenempTZeQfJfMa_bC7mt-yLD_BkLnMnKE,307
12
13
  wexample_wex_addon_dev_javascript/file/__init__.py,sha256=U4S_2y3zgLZVfMenHRaJFBW8yqh2mUBuI291LGQVOJ8,35
13
14
  wexample_wex_addon_dev_javascript/file/javascript_package_json_file.py,sha256=yn1ltv3oBYNg1OvUytJ4PEzH8FSJS2KcIKK8y-cMrl4,2906
@@ -25,7 +26,7 @@ wexample_wex_addon_dev_javascript/services/__init__.py,sha256=47DEQpj8HBSa-_TImW
25
26
  wexample_wex_addon_dev_javascript/services/node/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
26
27
  wexample_wex_addon_dev_javascript/services/node/commands/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
27
28
  wexample_wex_addon_dev_javascript/services/node/commands/service/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
28
- wexample_wex_addon_dev_javascript/services/node/commands/service/install_local.py,sha256=DtR5jrC2H_7h-TU1NhcH4TzzrqZ8_p7DMCfSQ7_GzsE,2773
29
+ wexample_wex_addon_dev_javascript/services/node/commands/service/install_local.py,sha256=U4WjWabvGhlET5zocCfKIT-1WwQJbRK0GOGD7krwTnE,3283
29
30
  wexample_wex_addon_dev_javascript/services/node/commands/service/refresh_lock.py,sha256=qlGmvYxjnXxrr1DILjBBLfp9kTruuBe-5SYEzxvVNIA,2204
30
31
  wexample_wex_addon_dev_javascript/services/node/docker/.wex.yml,sha256=JdIF6nGkFcfi76yZYGlXxeWfOK4eAUSV_gAn6i3hk2w,32
31
32
  wexample_wex_addon_dev_javascript/services/node/docker/docker-compose.yml,sha256=GF22uk3PDtywP_GAF0RbfJ7lQ5P5nuuwJQE9ohwQh28,362
@@ -45,7 +46,7 @@ wexample_wex_addon_dev_javascript/services/vite/docker/.wex.yml,sha256=JdIF6nGkF
45
46
  wexample_wex_addon_dev_javascript/services/vite/docker/docker-compose.yml,sha256=M7ejIcht0GxuEAEEcK3urBIrXA66JwYrr5EPUA9nMMM,595
46
47
  wexample_wex_addon_dev_javascript/services/vite/service.yml,sha256=8mFPv49QbKA3klHFbNK73QOB7ryy38zFeLiQB3gfDys,184
47
48
  wexample_wex_addon_dev_javascript/workdir/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
48
- wexample_wex_addon_dev_javascript/workdir/javascript_package_workdir.py,sha256=aUO2RdXlExfwIlnSexWGwc-Oh7QBMKKNv6sPgCIev2Q,9302
49
+ wexample_wex_addon_dev_javascript/workdir/javascript_package_workdir.py,sha256=mRTWei7NtmUzr5Ht1ZYVOdv_18tZ6BzruJMTuzy20s4,15612
49
50
  wexample_wex_addon_dev_javascript/workdir/javascript_packages_suite_workdir.py,sha256=b0QoTWlNYOYfpqEb8vYzL4WRoY0WwBhYOFUoRc4oySI,928
50
- wexample_wex_addon_dev_javascript/workdir/javascript_workdir.py,sha256=oKBj-tOV-EH9kqiXnKUE7sKLKU4v0ta4IQr-zLEWgFI,5272
51
- wexample_wex_addon_dev_javascript-8.1.5.dist-info/RECORD,,
51
+ wexample_wex_addon_dev_javascript/workdir/javascript_workdir.py,sha256=Wff6pgdPzsaf2zDfkVKytVHHp8rAXaXesz0G8Svh5z4,9529
52
+ wexample_wex_addon_dev_javascript-8.2.0.dist-info/RECORD,,
@@ -1,4 +1,4 @@
1
1
  Wheel-Version: 1.0
2
- Generator: pdm-backend (2.4.9)
2
+ Generator: pdm-backend (2.4.10)
3
3
  Root-Is-Purelib: true
4
4
  Tag: py3-none-any