@webex/common-timers 3.12.0-mobius-socket.3 → 3.12.0-next.10
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.repo-context.json +534 -0
- package/.sdd/manifest.json +268 -0
- package/AGENTS.md +240 -0
- package/docs/adr/index.md +34 -0
- package/docs/architecture.md +243 -0
- package/docs/getting-started.md +121 -0
- package/docs/index.md +50 -0
- package/docs/specs/README.md +86 -0
- package/package.json +5 -5
- package/schemas/repo-context.schema.json +796 -0
- package/src/docs/README.md +460 -0
|
@@ -0,0 +1,243 @@
|
|
|
1
|
+
---
|
|
2
|
+
type: Architecture
|
|
3
|
+
title: '@webex/common-timers architecture'
|
|
4
|
+
description: Repository-wide boundaries, resources, interactions, dependencies, and cross-cutting architecture.
|
|
5
|
+
tags: [architecture]
|
|
6
|
+
---
|
|
7
|
+
<!-- sdd-generated-metadata
|
|
8
|
+
doc_kind: standing-doc
|
|
9
|
+
generated_from: architecture@0.3.0
|
|
10
|
+
generated_by: claude-code
|
|
11
|
+
approved_by: pending
|
|
12
|
+
updated_at: 2026-09-28T05:34:36Z
|
|
13
|
+
validation_status: pass
|
|
14
|
+
-->
|
|
15
|
+
|
|
16
|
+
# @webex/common-timers architecture
|
|
17
|
+
|
|
18
|
+
Canonical architecture for the `@webex/common-timers` package. This document owns the facts that span
|
|
19
|
+
the package as a whole — what it is, what it publishes, what it depends on, and the platform and
|
|
20
|
+
release boundaries it sits inside. Behavior belongs to the owning module specification and is linked,
|
|
21
|
+
not repeated.
|
|
22
|
+
|
|
23
|
+
Related context: [specification registry](specs/README.md) ·
|
|
24
|
+
[repository agent instructions](../AGENTS.md)
|
|
25
|
+
|
|
26
|
+
## Applicability
|
|
27
|
+
|
|
28
|
+
| Condition ID | Status | Evidence or reason | Owned section |
|
|
29
|
+
| ------------------------------------ | ---------- | ----------------------------------------------------------------------------------------------------------------- | ----------------------------------- |
|
|
30
|
+
| `repo.owns_datastore` | N/A | No migrations, ORM configuration, schema file, or connection string exists | Repository data and schema |
|
|
31
|
+
| `repo.holds_client_state` | N/A | No store or shared state model; the only state is one private field per `Timer` instance | Client state model |
|
|
32
|
+
| `repo.components_interact` | N/A | The package is a single module with a single source file; there is no second component to interact with | Dependency and interaction topology |
|
|
33
|
+
| `repo.domain_data_across_components` | N/A | No domain entities exist; callbacks and durations are opaque values the package never inspects | Object and data ownership |
|
|
34
|
+
| `repo.caches_data` | N/A | No cache client, memoization, or bounded store | Caching catalog |
|
|
35
|
+
| `repo.observability_convention` | N/A | No logger, metric, trace, or audit call; the package emits nothing observable | Observability patterns |
|
|
36
|
+
| `repo.deploys_to_infra` | N/A | No container, manifest, or cloud configuration; the package is published to a registry, not deployed | Runtime and infrastructure |
|
|
37
|
+
| `repo.shared_base_libs` | Applicable | Build, lint, and test behavior are inherited from workspace-internal `@webex/*-legacy` packages | Shared and base libraries |
|
|
38
|
+
| `repo.is_monorepo` | N/A | The documented scope is one package; workspace-wide package mapping is owned outside it | Package map and dependencies |
|
|
39
|
+
| `repo.multi_platform` | Applicable | The `unref` capability check, the `process` browser shim, and the browserify transform encode a Node/browser split | Platform matrix |
|
|
40
|
+
| `repo.published_package` | Applicable | `package.json` declares `main`, `devMain`, and `deploy:npm` | Release and versioning |
|
|
41
|
+
| `repo.embedded_in_host` | N/A | Consumed as a dependency; no mount contract, plugin manifest, or widget registration | Host integration and theming |
|
|
42
|
+
| `repo.exposes_commands_or_artifacts` | N/A | No CLI, generator, or repository-owned command surface; the published build output is covered by Release and versioning | Commands and generated artifacts |
|
|
43
|
+
| `repo.cross_repo_deps_material` | N/A | The package declares no runtime dependencies, so nothing external can affect its behavior or delivery | Cross-repository topology |
|
|
44
|
+
| `repo.security_arch_warranted` | N/A | No identity, token, secret, encryption, or trust boundary; the posture is recorded under Cross-cutting architecture | Security architecture |
|
|
45
|
+
|
|
46
|
+
## Design overview
|
|
47
|
+
|
|
48
|
+
`@webex/common-timers` exists to solve one problem for every other package in the Webex JS SDK: a
|
|
49
|
+
pending timer must never be the reason a Node process refuses to exit.
|
|
50
|
+
|
|
51
|
+
Node's `setTimeout` and `setInterval` return a `Timeout` object that counts toward process liveness
|
|
52
|
+
until it fires or is cleared. An SDK that schedules retries, heartbeats, and batch flushes therefore
|
|
53
|
+
keeps a host CLI or test run alive long after the caller's work is done. Node's answer is
|
|
54
|
+
`Timeout.unref()`, and this package's answer is to make calling it unforgettable: the SDK imports
|
|
55
|
+
`safeSetTimeout` and `safeSetInterval` instead of the globals, and the `unref` call is built in.
|
|
56
|
+
|
|
57
|
+
That decision shapes everything else. Because browsers return a plain number with no `unref` method,
|
|
58
|
+
the wrappers feature-detect the method on the returned handle rather than branching on the platform —
|
|
59
|
+
so one module, one build, and no bundler shim serve both targets, at the cost of a
|
|
60
|
+
`number | NodeJS.Timeout` return type that every consumer has to accept.
|
|
61
|
+
|
|
62
|
+
A third export, `Timer`, sits on top. It is the one abstraction the free functions cannot express: a
|
|
63
|
+
deadline a caller can push back repeatedly and then retire, with a guarded `init → running → done`
|
|
64
|
+
lifecycle that throws rather than silently ignoring an invalid call. It arms itself through
|
|
65
|
+
`safeSetTimeout`, so a managed timer inherits the same process-exit safety.
|
|
66
|
+
|
|
67
|
+
The package is 117 lines in one file with zero runtime dependencies. Its architectural weight is
|
|
68
|
+
entirely in what it promises to the eleven workspace packages that consume it, not in its internal
|
|
69
|
+
structure.
|
|
70
|
+
|
|
71
|
+
## Resource inventory and responsibilities
|
|
72
|
+
|
|
73
|
+
| Resource | Kind | Responsibility | Owner | Source | Detailed specification |
|
|
74
|
+
| ---------------------- | ------- | --------------------------------------------------------------------------------------------------------- | -------------------------- | -------------- | ---------------------- |
|
|
75
|
+
| `@webex/common-timers` | Package | Publish the SDK's timer vocabulary to npm and to the surrounding workspace | Cisco Webex for Developers | `package.json` | `src/docs/README.md` |
|
|
76
|
+
| `src` | Module | The timer primitives themselves: both scheduling wrappers, the `unref` capability check, and the `Timer` lifecycle | Cisco Webex for Developers | `src/index.ts` | [`src/docs/README.md`](../src/docs/README.md) |
|
|
77
|
+
|
|
78
|
+
## Interaction and execution flows
|
|
79
|
+
|
|
80
|
+
The package has no internal interactions to diagram — one module, one file. The architecturally
|
|
81
|
+
meaningful flow is the one that crosses its boundary: a consuming SDK package calls in, the module
|
|
82
|
+
calls the host runtime, and the host calls the consumer's callback back directly.
|
|
83
|
+
|
|
84
|
+
```mermaid
|
|
85
|
+
flowchart LR
|
|
86
|
+
Consumer[Consuming SDK package] -->|import| Entry["src/index.ts"]
|
|
87
|
+
Entry -->|setTimeout / setInterval| Host[Host timer API]
|
|
88
|
+
Entry -->|unref when supported| Host
|
|
89
|
+
Host -.->|callback on the event loop| Consumer
|
|
90
|
+
Consumer -->|clearTimeout / clearInterval| Host
|
|
91
|
+
```
|
|
92
|
+
|
|
93
|
+
| From | To | Interaction or transport | Purpose | Failure or compatibility behavior |
|
|
94
|
+
| --------------------- | --------------------- | -------------------------------- | ------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------ |
|
|
95
|
+
| Consuming SDK package | `src` | Static import, synchronous call | Schedule deferred or repeating work, or bound a request with a resettable deadline | `Timer` throws synchronously on an invalid lifecycle call; the free functions have no rejected path |
|
|
96
|
+
| `src` | Host timer API | Direct call to the runtime global | Create the timer and release it from process liveness | Platform errors propagate unchanged. A missing `unref` is skipped silently, leaving the platform default |
|
|
97
|
+
| Host timer API | Consuming SDK package | Event-loop callback | Deliver the scheduled callback | A Node process may exit before the delay elapses, in which case the callback is never invoked at all |
|
|
98
|
+
| Consuming SDK package | Host timer API | Direct call to the runtime global | Cancel a timer using the returned handle | The package exports no clear function; cancellation uses the platform's own `clearTimeout` / `clearInterval` |
|
|
99
|
+
|
|
100
|
+
## Dependency topology
|
|
101
|
+
|
|
102
|
+
| Dependency | Type | Used by | Purpose | Version, failure, or fallback policy |
|
|
103
|
+
| --------------------------------------- | -------- | ------- | --------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------- |
|
|
104
|
+
| Host timer API | External | `src` | `setTimeout`, `setInterval`, and `clearTimeout` — the primitives being wrapped | No fallback and no polyfill. Whatever the runtime throws propagates to the caller unchanged |
|
|
105
|
+
| `Timeout.unref()` (Node-only extension) | External | `src` | Release a pending timer from process liveness | Feature-detected on the handle. Absent in browsers, where the branch is skipped and the platform default applies |
|
|
106
|
+
| `@webex/babel-config-legacy` | Internal | build | Transpilation configuration | `workspace:*`; development only, never shipped in the published artifact |
|
|
107
|
+
| `@webex/eslint-config-legacy` | Internal | lint | Lint rules | `workspace:*`; development only |
|
|
108
|
+
| `@webex/jest-config-legacy` | Internal | test | Unit-test configuration | `workspace:*`; development only |
|
|
109
|
+
| `@webex/legacy-tools` | Internal | build | The `webex-legacy-tools` build and test runner | `workspace:*`; development only |
|
|
110
|
+
|
|
111
|
+
There are **no runtime dependencies**: `package.json` declares only `devDependencies`. That removes
|
|
112
|
+
every cycle, ordering constraint, and third-party single point of failure from this package — the
|
|
113
|
+
only thing it can depend on at runtime is the host itself. Exact versions live in
|
|
114
|
+
[`package.json`](../package.json).
|
|
115
|
+
|
|
116
|
+
## Public and consumer surfaces
|
|
117
|
+
|
|
118
|
+
| Surface | Type | Owner | Consumers | Compatibility policy | Source |
|
|
119
|
+
| ---------------------- | ---- | ----- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------- | -------------- |
|
|
120
|
+
| `common-timers-sdk` | SDK | `src` | Declared by `internal-plugin-mercury`, `internal-plugin-metrics`, `internal-plugin-device`, `internal-plugin-encryption`, `internal-plugin-avatar`, `internal-plugin-dss`, `internal-plugin-ai-assistant`, `internal-plugin-scheduler`, `webex-core`, and `calling`; additionally imported, without being declared, by `plugin-meetings` | Published npm surface: `safeSetTimeout`, `safeSetInterval`, and `Timer`. Stable under the workspace's shared semantic version; the wrapper signatures track the platform's own | `package.json` |
|
|
121
|
+
|
|
122
|
+
`common-timers-sdk` is the package's only contract. Its canonical native source is the package entry
|
|
123
|
+
point declared by `main` and `devMain` in [`package.json`](../package.json); per-export detail,
|
|
124
|
+
including the parameter and return types, lives in the owning module specification's `Public surface`
|
|
125
|
+
and `Export stability` sections at [`src/docs/README.md`](../src/docs/README.md). This page indexes
|
|
126
|
+
the contract; it does not restate the declarations.
|
|
127
|
+
|
|
128
|
+
The declared and importing consumer sets differ in both directions, which matters for impact
|
|
129
|
+
analysis: `internal-plugin-scheduler` declares the dependency without importing it, and
|
|
130
|
+
`plugin-meetings` imports it without declaring it. A dependency-graph query over `package.json`
|
|
131
|
+
files alone therefore both over- and under-states the blast radius of a surface change. The module
|
|
132
|
+
specification records the per-export breakdown.
|
|
133
|
+
|
|
134
|
+
The package consumes one external contract, `host-timer-api` — the runtime's own
|
|
135
|
+
`setTimeout`/`setInterval`/`clearTimeout` plus the Node `Timeout.unref()` extension. It is external
|
|
136
|
+
and unversioned by this repository; its consumption is recorded in the module spec's `Dependencies`.
|
|
137
|
+
|
|
138
|
+
## Cross-cutting architecture
|
|
139
|
+
|
|
140
|
+
### Security
|
|
141
|
+
|
|
142
|
+
- **Trust boundaries and identity flow:** none. The package has no identity, no authentication, and
|
|
143
|
+
no trust boundary. It never reads configuration, never touches the network, and never inspects the
|
|
144
|
+
callback or duration a caller passes it.
|
|
145
|
+
- **Sensitive surfaces and data classes:** none. No data of any classification transits the package;
|
|
146
|
+
arguments are forwarded to the host scheduler and never stored, logged, or serialized.
|
|
147
|
+
- **Encryption and secret boundaries:** not applicable. Nothing is persisted or transmitted.
|
|
148
|
+
|
|
149
|
+
The security-relevant property of this package is a liveness one, not a confidentiality one: because
|
|
150
|
+
every timer is unref-ed, the package can cause scheduled work to be silently dropped at process exit.
|
|
151
|
+
Consumers that require a callback to run before shutdown must hold the process open themselves.
|
|
152
|
+
|
|
153
|
+
### Observability and operations
|
|
154
|
+
|
|
155
|
+
- **Logging and correlation:** none. The package emits no log line, and deliberately takes no logger
|
|
156
|
+
dependency — a timer primitive called from ten packages would produce noise with no correlation
|
|
157
|
+
context of its own. Consumers log around their own timer usage.
|
|
158
|
+
- **Metrics, traces, and audit signals:** none emitted or consumed.
|
|
159
|
+
- **Ownership and operational entry points:** the package is maintained by Cisco Webex for Developers
|
|
160
|
+
as part of the Webex JS SDK workspace; it has no dashboard, alert, or runbook of its own because it
|
|
161
|
+
has no runtime deployment. Failures surface inside the consuming package.
|
|
162
|
+
|
|
163
|
+
### Quality attributes
|
|
164
|
+
|
|
165
|
+
The measurable expectations that fit a dependency-free utility package of this size:
|
|
166
|
+
|
|
167
|
+
| Attribute | Expectation | Evidence |
|
|
168
|
+
| ------------------------- | ---------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------- |
|
|
169
|
+
| Footprint | Zero runtime dependencies; the published artifact is one transpiled module | `package.json` |
|
|
170
|
+
| Platform compatibility | The same build runs on Node `>=18` and in a browser, with no conditional export or bundler shim | `package.json`, `src/index.ts`, `process` |
|
|
171
|
+
| Process-exit safety | No timer created through this package extends process lifetime | `src/index.ts` |
|
|
172
|
+
| Lifecycle correctness | Every invalid `Timer` transition is rejected rather than ignored; all six rejection branches are covered by unit tests | `test/unit/spec/index.ts` |
|
|
173
|
+
| Process-exit verification | **Not verified by test.** No assertion covers the `unref` contract on either platform branch | `src/index.ts` (code reading only) |
|
|
174
|
+
| Test verification | 13 unit cases in one suite, all passing. No coverage threshold gates the package — coverage collection is disabled in its jest config | `test/unit/spec/index.ts`, `jest.config.js` |
|
|
175
|
+
|
|
176
|
+
Process-exit safety is the attribute that most needs proving and is the one still unproven: the
|
|
177
|
+
`unref` calls in `src/index.ts` carry no test, so removing them would not turn the suite red. The
|
|
178
|
+
attribute is supported by code reading alone. Lifecycle correctness, by contrast, is thoroughly
|
|
179
|
+
covered. Per-requirement evidence and the full list of coverage gaps are recorded in the module
|
|
180
|
+
specification's `Verification` section.
|
|
181
|
+
|
|
182
|
+
## Shared and base libraries
|
|
183
|
+
|
|
184
|
+
Every build, lint, and test behavior in this package is inherited. The package contributes three
|
|
185
|
+
two-line configuration files that do nothing but re-export the shared configuration.
|
|
186
|
+
|
|
187
|
+
| Library | Inherited responsibility | Consumers | Version floor | Compatibility rule |
|
|
188
|
+
| ----------------------------- | -------------------------------------------------------------------------------- | --------------------------- | ------------- | ------------------------------------------------------------------------------------------ |
|
|
189
|
+
| `@webex/babel-config-legacy` | Transpilation targets and plugins, re-exported verbatim by `babel.config.js` | Build | `workspace:*` | Pinned to the workspace; a change to the shared config changes this package's output |
|
|
190
|
+
| `@webex/eslint-config-legacy` | All lint rules, extended by `.eslintrc.js` with `root: true` and nothing else | `test:style` | `workspace:*` | Pinned to the workspace; this package adds no local rule or override |
|
|
191
|
+
| `@webex/jest-config-legacy` | Unit-test runner configuration, re-exported verbatim by `jest.config.js` | `test:unit` | `workspace:*` | Pinned to the workspace. It sets `collectCoverage: false`, which is why no gate applies here |
|
|
192
|
+
| `@webex/legacy-tools` | The `webex-legacy-tools` build and test CLI invoked by the package scripts | `build:src`, `test:unit` | `workspace:*` | Pinned to the workspace; command flags are owned there, not here |
|
|
193
|
+
|
|
194
|
+
The practical consequence for a contributor: there is no package-local knob. Changing how this
|
|
195
|
+
package builds, lints, or tests means changing the shared workspace configuration.
|
|
196
|
+
|
|
197
|
+
## Platform matrix
|
|
198
|
+
|
|
199
|
+
The package targets Node and the browser from one source file and one build. The split is a single
|
|
200
|
+
runtime capability check, not a build-time branch.
|
|
201
|
+
|
|
202
|
+
| Platform | Shared versus platform-specific boundary | Entry or build | Support and compatibility constraints |
|
|
203
|
+
| -------- | ----------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------ | ----------------------------------------------------------------------------------------------------------------------------------- |
|
|
204
|
+
| Node | Fully shared. The handle is a `Timeout` object exposing `unref`, so the capability check succeeds and the timer is released from process liveness | `dist/index.js` via `main`, built by `build:src` | Requires Node `>=18` per `engines`. Scheduled callbacks may be dropped at process exit — that is the intended behavior |
|
|
205
|
+
| Browser | Fully shared. The handle is a number with no `unref`, so the check fails and the platform default applies | Same module; the browserify transform resolves the `process` shim to `{browser: true}` | No separate bundle, no `browser` field in `package.json`, and no polyfill. Behavior degrades to plain `setTimeout`/`setInterval` |
|
|
206
|
+
|
|
207
|
+
Because the two platforms return different handle types, the exported return type is the union
|
|
208
|
+
`number | NodeJS.Timeout`. That union is the visible cost of the single-build decision, and it is
|
|
209
|
+
part of the published contract rather than an implementation detail.
|
|
210
|
+
|
|
211
|
+
## Release and versioning
|
|
212
|
+
|
|
213
|
+
| Artifact | Publish target | Versioning rule | Deprecation window | Changelog or migration obligation |
|
|
214
|
+
| ---------------------- | -------------- | ------------------------------------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------ |
|
|
215
|
+
| `@webex/common-timers` | npm | Published by `deploy:npm`. Version numbers are assigned by the workspace release pipeline, not declared in this package's `package.json` | Governed by the workspace release process; the package declares none of its own | Changelog generation is owned at the workspace root. This package ships no `CHANGELOG.md` |
|
|
216
|
+
|
|
217
|
+
The published artifact is `dist/index.js`, produced by `build:src`. In-workspace consumers resolve
|
|
218
|
+
`devMain` (`src/index.ts`) instead, so a change to the source is visible to sibling packages without
|
|
219
|
+
a publish. A breaking change to any of the three exports is a breaking change for eleven workspace
|
|
220
|
+
packages plus external npm consumers; the module specification's `Export stability` section records
|
|
221
|
+
what specifically is promised, including that the `Timer` rejection message wording is asserted by
|
|
222
|
+
the unit suite.
|
|
223
|
+
|
|
224
|
+
## Domain language
|
|
225
|
+
|
|
226
|
+
| Term | Repository-specific meaning | Authoritative source |
|
|
227
|
+
| ---------------- | ------------------------------------------------------------------------------------------------------------------------------------------------- | -------------------- |
|
|
228
|
+
| unref | Asking a Node timer handle to stop counting toward process liveness, so a pending timer cannot prevent the process from exiting | `src/index.ts` |
|
|
229
|
+
| safe | In `safeSetTimeout` / `safeSetInterval`, specifically "safe against wedging a process open" — it implies nothing about error handling or types | `README.md` |
|
|
230
|
+
| handle | The value the host scheduler returns: a `Timeout` object in Node, a number in a browser. The package returns it unchanged after unref-ing it | `src/index.ts` |
|
|
231
|
+
| arm | Move a `Timer` from `init` to `running` by scheduling its callback. Only `start()` arms a timer | `src/index.ts` |
|
|
232
|
+
| reset | Clear a running timer and re-arm it for the **full** original timeout. It is an idle deadline, not a pause or a resume | `src/index.ts` |
|
|
233
|
+
| done | The terminal `Timer` state, reached by either expiry or cancellation. It is not recoverable and the two causes are indistinguishable | `src/index.ts` |
|
|
234
|
+
|
|
235
|
+
## References and maintenance
|
|
236
|
+
|
|
237
|
+
- Decisions: [adr/](adr/)
|
|
238
|
+
- Instantiated specifications and routing: [specs/README.md](specs/README.md)
|
|
239
|
+
- Module specification: [`src/docs/README.md`](../src/docs/README.md)
|
|
240
|
+
- Getting started: [getting-started.md](getting-started.md)
|
|
241
|
+
- Update this document in the same change that alters the package's published surface, its
|
|
242
|
+
dependency posture, its platform support, or its release boundary. A change confined to timer
|
|
243
|
+
behavior belongs in the module specification instead.
|
|
@@ -0,0 +1,121 @@
|
|
|
1
|
+
---
|
|
2
|
+
type: Getting Started
|
|
3
|
+
title: Getting started
|
|
4
|
+
description: Local setup, build, run, and test routing for @webex/common-timers.
|
|
5
|
+
tags: [onboarding]
|
|
6
|
+
---
|
|
7
|
+
<!-- sdd-generated-metadata
|
|
8
|
+
doc_kind: standing-doc
|
|
9
|
+
generated_from: getting-started@0.3.0
|
|
10
|
+
generated_by: claude-code
|
|
11
|
+
approved_by: pending
|
|
12
|
+
updated_at: 2026-09-28T05:34:36Z
|
|
13
|
+
validation_status: pass
|
|
14
|
+
-->
|
|
15
|
+
|
|
16
|
+
# Getting started
|
|
17
|
+
|
|
18
|
+
Onboarding for **`@webex/common-timers`**. The package is one of many in the Webex JS SDK yarn
|
|
19
|
+
workspace, so every command below is run from the workspace root and targets this package by name.
|
|
20
|
+
|
|
21
|
+
## Prerequisites
|
|
22
|
+
|
|
23
|
+
| Tool or access | Version or requirement |
|
|
24
|
+
| -------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
|
|
25
|
+
| Node.js | `package.json` declares the package floor as `>=18`. The surrounding workspace pins a newer Node through its own `.nvmrc` and contributor instructions, so match the workspace when working in-tree |
|
|
26
|
+
| Yarn | The workspace ships its own Yarn release and resolves it automatically; do not install Yarn separately |
|
|
27
|
+
| Registry, VPN, or account access | N/A. The package has no runtime dependencies and resolves nothing from a private registry |
|
|
28
|
+
|
|
29
|
+
## Install
|
|
30
|
+
|
|
31
|
+
```bash
|
|
32
|
+
yarn install
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
Run `yarn install` once at the Webex JS SDK workspace root. It installs every package in the
|
|
36
|
+
workspace, including this one; there is no package-local install step.
|
|
37
|
+
|
|
38
|
+
Cloning the workspace is owned at the workspace root, not by this package, so no clone command is
|
|
39
|
+
recorded here — follow the root repository's own instructions to obtain a checkout first.
|
|
40
|
+
|
|
41
|
+
## Build
|
|
42
|
+
|
|
43
|
+
```bash
|
|
44
|
+
yarn workspace @webex/common-timers build:src
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
This runs `webex-legacy-tools build` over `src/` and writes the transpiled module plus type
|
|
48
|
+
declarations and source maps to `dist/`, which is what `main` points at for published consumers.
|
|
49
|
+
`yarn workspace @webex/common-timers build` is an alias for the same thing.
|
|
50
|
+
|
|
51
|
+
## Run
|
|
52
|
+
|
|
53
|
+
```bash
|
|
54
|
+
# N/A — this package has no runnable entry point.
|
|
55
|
+
yarn workspace @webex/common-timers test:unit
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
There is nothing to start. The package is a library with no CLI, server, or runtime entry point —
|
|
59
|
+
`package.json` declares no `bin` and no `start` script. The closest thing to running it is executing
|
|
60
|
+
its unit suite, or importing it from a sibling workspace package, which resolves `devMain`
|
|
61
|
+
(`src/index.ts`) directly without a build.
|
|
62
|
+
|
|
63
|
+
## Tests
|
|
64
|
+
|
|
65
|
+
```bash
|
|
66
|
+
yarn workspace @webex/common-timers test:unit
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
The package declares exactly one test tier. `package.json` also declares an aggregate `test` script,
|
|
70
|
+
but it chains `test:integration` and `test:browser`, neither of which this package defines — so
|
|
71
|
+
`yarn workspace @webex/common-timers test` cannot succeed. Use the individual commands.
|
|
72
|
+
|
|
73
|
+
| Tier | Command | Test location | Framework | External dependencies |
|
|
74
|
+
| ---- | -------------------------------------------------- | ------------------------- | --------- | --------------------- |
|
|
75
|
+
| Unit | `yarn workspace @webex/common-timers test:unit` | `test/unit/spec/index.ts` | jest | None |
|
|
76
|
+
|
|
77
|
+
Lint runs separately:
|
|
78
|
+
|
|
79
|
+
```bash
|
|
80
|
+
yarn workspace @webex/common-timers test:style
|
|
81
|
+
```
|
|
82
|
+
|
|
83
|
+
- Coverage or quality gate: N/A. The resolved `jest.config.js` sets `collectCoverage: false` and
|
|
84
|
+
declares no threshold, and the package has no `test:coverage` script for the workspace CI coverage
|
|
85
|
+
job to pick up. Verified with the package owner during onboarding.
|
|
86
|
+
- Enforcement source: `jest.config.js`, which re-exports the shared `@webex/jest-config-legacy`
|
|
87
|
+
configuration
|
|
88
|
+
- Test environment or QA dependencies: none. The suite runs entirely in-process against sinon fake
|
|
89
|
+
timers
|
|
90
|
+
|
|
91
|
+
## Configuration and secrets
|
|
92
|
+
|
|
93
|
+
- Required configuration: none. The package reads no environment variable, config file, or remote
|
|
94
|
+
setting.
|
|
95
|
+
- Secret source: N/A — the package handles no credentials.
|
|
96
|
+
- Package or artifact access: N/A — no runtime dependencies and no private registry.
|
|
97
|
+
- Required neighboring repositories or workspace layout: the package must be built and tested from
|
|
98
|
+
inside the Webex JS SDK workspace, because its build, lint, and test configuration are all
|
|
99
|
+
`workspace:*` dependencies (`@webex/legacy-tools`, `@webex/jest-config-legacy`,
|
|
100
|
+
`@webex/eslint-config-legacy`, `@webex/babel-config-legacy`).
|
|
101
|
+
- Platform, simulator, device, or SDK setup: N/A.
|
|
102
|
+
- Never commit credentials or copy production secrets into a local config.
|
|
103
|
+
|
|
104
|
+
## First-run verification
|
|
105
|
+
|
|
106
|
+
1. Run `yarn install` at the workspace root.
|
|
107
|
+
2. Run `yarn workspace @webex/common-timers test:unit`.
|
|
108
|
+
3. Run `yarn workspace @webex/common-timers build:src` and confirm `dist/index.js` exists.
|
|
109
|
+
|
|
110
|
+
Expected result: the unit suite reports **13 passed, 13 total** from the single suite at
|
|
111
|
+
`test/unit/spec/index.ts`, covering `safeSetTimeout` callback delivery, `safeSetInterval` repetition,
|
|
112
|
+
and the three `Timer` methods with all six rejected transitions. The `unref` contract is not
|
|
113
|
+
asserted anywhere; see the module spec's `Verification` section. The build writes `dist/`.
|
|
114
|
+
|
|
115
|
+
## Next steps
|
|
116
|
+
|
|
117
|
+
- [Repository architecture](architecture.md)
|
|
118
|
+
- [Specification registry](specs/README.md)
|
|
119
|
+
- [Module specification](../src/docs/README.md) — the behavior contract, state machine, and known
|
|
120
|
+
test gaps
|
|
121
|
+
- [Documentation index](index.md)
|
package/docs/index.md
ADDED
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
---
|
|
2
|
+
okf_version: '0.1'
|
|
3
|
+
---
|
|
4
|
+
<!-- sdd-generated-metadata
|
|
5
|
+
doc_kind: standing-doc
|
|
6
|
+
generated_from: docs-index@0.3.0
|
|
7
|
+
generated_by: claude-code
|
|
8
|
+
approved_by: pending
|
|
9
|
+
updated_at: 2026-09-28T05:34:36Z
|
|
10
|
+
validation_status: pass
|
|
11
|
+
-->
|
|
12
|
+
|
|
13
|
+
# @webex/common-timers documentation
|
|
14
|
+
|
|
15
|
+
Doc map for developers and agents working on the timer primitives the Webex JS SDK schedules all of
|
|
16
|
+
its deferred work through.
|
|
17
|
+
|
|
18
|
+
## Start here
|
|
19
|
+
|
|
20
|
+
- [Getting started](getting-started.md) — prerequisites, build, and the test router
|
|
21
|
+
- [Repository architecture](architecture.md) — what the package publishes, what it depends on, and
|
|
22
|
+
the platform and release boundaries it sits inside
|
|
23
|
+
|
|
24
|
+
There is no service specification and no API specification for this package: it is a published
|
|
25
|
+
library with no deployable runtime and no HTTP surface. Both omissions are recorded in
|
|
26
|
+
`.sdd/manifest.json` under `layout.artifact_decisions`.
|
|
27
|
+
|
|
28
|
+
## Decisions
|
|
29
|
+
|
|
30
|
+
- [adr/](adr/) — architectural decision records. None are registered yet; the decisions that shape
|
|
31
|
+
the current design are recorded in the module specification's `Key design trade-off` section.
|
|
32
|
+
|
|
33
|
+
## Specifications and contracts
|
|
34
|
+
|
|
35
|
+
- [architecture.md](architecture.md) — canonical package-wide architecture and the contract index
|
|
36
|
+
- [specs/README.md](specs/README.md) — module and specification registry
|
|
37
|
+
- [`src/docs/README.md`](../src/docs/README.md) — the owning specification beside the module's code:
|
|
38
|
+
public surface, requirements, state machine, failure modes, and verification
|
|
39
|
+
- [adr/](adr/) — concrete architectural decisions; the blank ADR template stays under `.sdd/`
|
|
40
|
+
|
|
41
|
+
The package's one contract, `common-timers-sdk`, is a published npm package surface. Its native
|
|
42
|
+
source is the entry point declared by `main` and `devMain` in [`package.json`](../package.json), and
|
|
43
|
+
the exact declarations live in [`src/index.ts`](../src/index.ts). The architecture page indexes that
|
|
44
|
+
contract and the module specification details it; neither copies the declarations into Markdown.
|
|
45
|
+
|
|
46
|
+
## Related repository resources
|
|
47
|
+
|
|
48
|
+
- [`README.md`](../README.md) — the package's npm-facing readme, covering install and basic usage
|
|
49
|
+
- Contribution guidelines, changelog generation, and the release pipeline are owned at the Webex JS
|
|
50
|
+
SDK workspace root, not in this package
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
---
|
|
2
|
+
type: Reference
|
|
3
|
+
title: Specification registry
|
|
4
|
+
description: Canonical specification registry and change-routing guide.
|
|
5
|
+
tags: [specifications, registry]
|
|
6
|
+
---
|
|
7
|
+
<!-- sdd-generated-metadata
|
|
8
|
+
doc_kind: standing-doc
|
|
9
|
+
generated_from: spec-index@0.3.0
|
|
10
|
+
generated_by: claude-code
|
|
11
|
+
approved_by: pending
|
|
12
|
+
updated_at: 2026-09-28T05:34:36Z
|
|
13
|
+
validation_status: pass
|
|
14
|
+
-->
|
|
15
|
+
|
|
16
|
+
# Specification registry
|
|
17
|
+
|
|
18
|
+
Use this page to find the canonical architecture for `@webex/common-timers` and every instantiated
|
|
19
|
+
module specification plus native contract. Technical facts stay in one owning document; this page is
|
|
20
|
+
navigation, ownership, status, and change/test routing only.
|
|
21
|
+
|
|
22
|
+
Start with the [repository architecture](../architecture.md). There is no service specification: the
|
|
23
|
+
package is a published library, not a deployable service.
|
|
24
|
+
|
|
25
|
+
## Document roles
|
|
26
|
+
|
|
27
|
+
| Document | Canonical ownership |
|
|
28
|
+
| ---------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------- |
|
|
29
|
+
| [Repository architecture](../architecture.md) | Package boundaries, resource inventory, interactions, dependency topology, and cross-cutting architecture |
|
|
30
|
+
| Service specification | N/A — not generated. The package has no deployable runtime, so no service or operating contract exists |
|
|
31
|
+
| Module specifications | Stable behavior and design at each module's `docs/README.md`, routed by `.sdd/manifest.json` |
|
|
32
|
+
| [ADR](../adr/) | A durable decision, its deciders, rationale, consequences, and supersession lineage. None are registered yet |
|
|
33
|
+
|
|
34
|
+
## Instantiated specification registry
|
|
35
|
+
|
|
36
|
+
| Resource | Role | Canonical path | Owner | Status | Last verified |
|
|
37
|
+
| ---------------------- | ------------ | ---------------------- | -------------------------- | ------ | ------------- |
|
|
38
|
+
| `@webex/common-timers` | Architecture | `docs/architecture.md` | Cisco Webex for Developers | Active | 2026-09-28 |
|
|
39
|
+
| `src` | Module | `src/docs/README.md` | Cisco Webex for Developers | Active | 2026-09-28 |
|
|
40
|
+
| `common-timers-sdk` | Contract | `package.json` | Cisco Webex for Developers | Active | 2026-09-28 |
|
|
41
|
+
|
|
42
|
+
### Module registry
|
|
43
|
+
|
|
44
|
+
One row per module in `.sdd/manifest.json`, which stays authoritative; this table is its
|
|
45
|
+
human-readable mirror and the reconciliation surface for `check_spec_index.py`.
|
|
46
|
+
|
|
47
|
+
| Module | Responsibility | Manifest coverage state | Start here |
|
|
48
|
+
| --- | --- | --- | --- |
|
|
49
|
+
| `src/` | Timer primitives that never hold a Node process open: unref-ing wrappers over `setTimeout` and `setInterval`, plus the guarded `Timer` lifecycle | Partial | `src/docs/README.md` |
|
|
50
|
+
|
|
51
|
+
Generator-side field measurement for `src` is complete: 100% (14 of 14 mandatory fields) assessed
|
|
52
|
+
2026-09-24, with critical field coverage at 9 of 9. The score, date, and evidence summary are
|
|
53
|
+
recorded in the module specification's `Coverage score` metadata row and in `.sdd/manifest.json`.
|
|
54
|
+
|
|
55
|
+
Two gates still hold promotion open. This module has no characterization baseline, and the `unref`
|
|
56
|
+
requirements (`MOD-002`, `MOD-004`, `MOD-012`) together with the re-entrancy requirement (`MOD-009`)
|
|
57
|
+
have no automated evidence; the sole test file, `test/unit/spec/index.ts`, is pre-existing and covers
|
|
58
|
+
the `Timer` lifecycle rather than the `unref` contract. Independent validation (validator `codex`,
|
|
59
|
+
2026-09-24) returned blocked across two runs, raising three findings in total — consumer-inventory
|
|
60
|
+
drift, an onboarding command with no manifest entry, and evidence-column anchors that were not
|
|
61
|
+
repository file paths. All three were repaired and the third run returned pass-with-warnings. A later
|
|
62
|
+
run assessed a test suite that has since been withdrawn from this change, so that result is stale.
|
|
63
|
+
`src` stays `Partial` until the missing assertions and a characterization baseline exist and a fresh
|
|
64
|
+
validation covers them.
|
|
65
|
+
|
|
66
|
+
## Change and verification routing
|
|
67
|
+
|
|
68
|
+
| Change affects | Load and update | Verification route |
|
|
69
|
+
| ------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------ |
|
|
70
|
+
| Package boundaries, dependency posture, platform support, or release | `docs/architecture.md`, and a new ADR under `docs/adr/` when the decision is durable | `yarn workspace @webex/common-timers build:src` plus the affected module spec |
|
|
71
|
+
| Timer behavior, the `Timer` lifecycle, or a thrown message | `src/docs/README.md` — `Requirements`, `State machine`, `Caller-visible failure modes`, `Verification` | `yarn workspace @webex/common-timers test:unit` |
|
|
72
|
+
| The exported surface or its types | `src/docs/README.md` — `Public surface` and `Export stability` — plus the architecture contract index | `yarn workspace @webex/common-timers build:src` and every dependent package's unit suite |
|
|
73
|
+
| Build, lint, or test configuration | `docs/getting-started.md` and the architecture `Shared and base libraries` section | `yarn workspace @webex/common-timers test:style` and `test:unit` |
|
|
74
|
+
|
|
75
|
+
## Module and contract registration
|
|
76
|
+
|
|
77
|
+
The module specification is generated at the exact `modules[].canonical_spec` path recorded in
|
|
78
|
+
`.sdd/manifest.json` — `src/docs/README.md`. Every module and submodule is registered in the Module
|
|
79
|
+
registry above in manifest tree order; `src` has no submodules.
|
|
80
|
+
|
|
81
|
+
`common-timers-sdk` is the package's only contract: a published SDK/package surface whose canonical
|
|
82
|
+
native source is the entry point declared by `main` and `devMain` in `package.json`, with the exact
|
|
83
|
+
declarations in `src/index.ts`. Published package surfaces retain their ecosystem-native API source
|
|
84
|
+
and do not require OpenAPI, and the package serves no HTTP routes, so `api-specs/openapi.yaml` is
|
|
85
|
+
omitted. The module also consumes one external contract, `host-timer-api`, the host runtime's timer
|
|
86
|
+
API. This page provides navigation and ownership rather than a copied contract.
|
package/package.json
CHANGED
|
@@ -32,12 +32,12 @@
|
|
|
32
32
|
"@webex/eslint-config-legacy": "0.0.0",
|
|
33
33
|
"@webex/jest-config-legacy": "0.0.0",
|
|
34
34
|
"@webex/legacy-tools": "0.0.0",
|
|
35
|
-
"@webex/test-helper-chai": "3.12.0-
|
|
36
|
-
"@webex/test-helper-mocha": "3.12.0-
|
|
37
|
-
"@webex/test-helper-mock-webex": "3.12.0-
|
|
38
|
-
"@webex/test-helper-test-users": "3.12.0-
|
|
35
|
+
"@webex/test-helper-chai": "3.12.0-next.9",
|
|
36
|
+
"@webex/test-helper-mocha": "3.12.0-next.9",
|
|
37
|
+
"@webex/test-helper-mock-webex": "3.12.0-next.9",
|
|
38
|
+
"@webex/test-helper-test-users": "3.12.0-next.9",
|
|
39
39
|
"eslint": "^8.24.0",
|
|
40
40
|
"prettier": "^2.7.1"
|
|
41
41
|
},
|
|
42
|
-
"version": "3.12.0-
|
|
42
|
+
"version": "3.12.0-next.10"
|
|
43
43
|
}
|