@deepseek-ai/dsh-util-time 0.1.2-alpha.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.i18n.yaml +6 -0
- package/README.md +68 -0
- package/README.zh.md +68 -0
- package/lib/index.js +31 -0
- package/lib/invariant.js +23 -0
- package/lib/types/index.d.ts +17 -0
- package/lib/types/invariant.d.ts +16 -0
- package/package.json +42 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 DeepSeek
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.i18n.yaml
ADDED
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
# Bilingual-pair consistency record (docs/i18n/README.md): the git blob hash of each
|
|
2
|
+
# side as of the last confirmed-consistent state. Both languages carry equal authority;
|
|
3
|
+
# after editing either side, bring the other along and re-record with:
|
|
4
|
+
# pnpm run verify-translation-pairing --write packages/util/time/README.md
|
|
5
|
+
README.md: 40f6b4d9ef50f0f35eb9b143ed31cccce352647c
|
|
6
|
+
README.zh.md: f6648415dc1ab89382f92e9f0e6ab9465e7fc2b1
|
package/README.md
ADDED
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
---
|
|
2
|
+
description: "IANA time-zone validation and canonicalization for maintainers accepting a caller-reported zone at a wire boundary."
|
|
3
|
+
kind: "package-library"
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# dsh-util-time
|
|
7
|
+
|
|
8
|
+
English | [中文](README.zh.md)
|
|
9
|
+
|
|
10
|
+
## Summary
|
|
11
|
+
|
|
12
|
+
Zero-dependency zone vocabulary for the wire boundaries that accept a caller's time zone. `canonicalClientTimeZone` admits `UTC` or an IANA `Area/Location` name and answers the platform-canonical spelling of it, so an alias never reaches a durable record: a zone identity is stored on messages and re-derived later by another process, where an alias would not compare equal. The library validates and canonicalizes only — it formats no time and owns no failure vocabulary, because each boundary throws its own domain code.
|
|
13
|
+
|
|
14
|
+
## Table of Contents
|
|
15
|
+
|
|
16
|
+
- [Use this package](#use-this-package)
|
|
17
|
+
- [API](#api)
|
|
18
|
+
- [Model Experience](#model-experience)
|
|
19
|
+
- [Known Limitations and Deferred Work](#known-limitations-and-deferred-work)
|
|
20
|
+
- [Dev Note](#dev-note)
|
|
21
|
+
|
|
22
|
+
-----
|
|
23
|
+
|
|
24
|
+
<a id="use-this-package"></a>
|
|
25
|
+
## Use this package
|
|
26
|
+
|
|
27
|
+
It is a **library, not a service or plugin**: no `ctx`, registers nothing, holds no state.
|
|
28
|
+
|
|
29
|
+
Call it at the boundary that receives the zone, before the value reaches anything durable. An unusable name answers `undefined`, and the caller raises its own refusal — `session/invalid-time-zone` for the Session prompt, `subagent/invalid-time-zone` for a subagent continuation.
|
|
30
|
+
|
|
31
|
+
-----
|
|
32
|
+
|
|
33
|
+
<a id="api"></a>
|
|
34
|
+
## API
|
|
35
|
+
|
|
36
|
+
```ts
|
|
37
|
+
import { canonicalClientTimeZone } from '@deepseek-ai/dsh-util-time'
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
| Export | Role |
|
|
41
|
+
|---|---|
|
|
42
|
+
| `canonicalClientTimeZone(value)` | Canonical `UTC` or IANA `Area/Location` name for an accepted zone, `undefined` for a blank, padded, abbreviated, single-segment, or platform-unsupported one. |
|
|
43
|
+
|
|
44
|
+
<a id="model-experience"></a>
|
|
45
|
+
## Model Experience
|
|
46
|
+
|
|
47
|
+
Indirectly, through the consumer that records a canonical zone on a durable message, from which `dsh-time-context` renders the turn's model-visible zone instruction and timestamp.
|
|
48
|
+
|
|
49
|
+
#### KV Cache effect
|
|
50
|
+
|
|
51
|
+
None of its own. The consumer that injects a zone-derived line into a request owns that request's cache behavior.
|
|
52
|
+
|
|
53
|
+
## Known Limitations and Deferred Work
|
|
54
|
+
|
|
55
|
+
<a id="known-limitations-and-deferred-work"></a>
|
|
56
|
+
|
|
57
|
+
- **Alias resolution follows the runtime's ICU data** — which name an alias group canonicalizes to is the platform's answer, so two processes on different Node builds can disagree about it.
|
|
58
|
+
- **Validation only** — no formatting, offset arithmetic, DST reasoning, or instant conversion; consumers needing those use `Intl` directly.
|
|
59
|
+
|
|
60
|
+
<a id="dev-note"></a>
|
|
61
|
+
### Dev Note
|
|
62
|
+
|
|
63
|
+
<details>
|
|
64
|
+
<summary>Working context for maintainers — click to expand</summary>
|
|
65
|
+
|
|
66
|
+
None.
|
|
67
|
+
|
|
68
|
+
</details>
|
package/README.zh.md
ADDED
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
---
|
|
2
|
+
description: "面向在协议边界接收调用方所报时区的维护者,说明 IANA 时区校验与规范化。"
|
|
3
|
+
kind: "package-library"
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# dsh-util-time
|
|
7
|
+
|
|
8
|
+
[English](README.md) | 中文
|
|
9
|
+
|
|
10
|
+
## 概述
|
|
11
|
+
|
|
12
|
+
零依赖的时区词汇,供接收调用方时区的协议边界使用。`canonicalClientTimeZone` 只接受 `UTC` 或 IANA `Area/Location` 名称,并回答该名称在当前平台上的规范拼写,因此别名不会进入持久记录:时区标识会存在消息上、并由另一个进程稍后重新推导,别名在那里比不相等。本库只做校验与规范化——不格式化任何时间,也不持有失败词汇,因为每个边界抛自己的域码。
|
|
13
|
+
|
|
14
|
+
## 目录
|
|
15
|
+
|
|
16
|
+
- [使用本包](#use-this-package)
|
|
17
|
+
- [API](#api)
|
|
18
|
+
- [Model Experience](#model-experience)
|
|
19
|
+
- [Known Limitations and Deferred Work](#known-limitations-and-deferred-work)
|
|
20
|
+
- [开发备注](#dev-note)
|
|
21
|
+
|
|
22
|
+
-----
|
|
23
|
+
|
|
24
|
+
<a id="use-this-package"></a>
|
|
25
|
+
## 使用本包
|
|
26
|
+
|
|
27
|
+
它是**库,不是服务也不是插件**:无 `ctx`、不注册任何东西、不持有状态。
|
|
28
|
+
|
|
29
|
+
在接收时区的那个边界上调用它,让值在进入任何持久物之前先过一遍。不可用的名称回答 `undefined`,由调用方抛出自己的拒绝——Session prompt 用 `session/invalid-time-zone`,subagent 续话用 `subagent/invalid-time-zone`。
|
|
30
|
+
|
|
31
|
+
-----
|
|
32
|
+
|
|
33
|
+
<a id="api"></a>
|
|
34
|
+
## API
|
|
35
|
+
|
|
36
|
+
```ts
|
|
37
|
+
import { canonicalClientTimeZone } from '@deepseek-ai/dsh-util-time'
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
| 导出 | 职责 |
|
|
41
|
+
|---|---|
|
|
42
|
+
| `canonicalClientTimeZone(value)` | 对接受的时区回答规范的 `UTC` 或 IANA `Area/Location` 名称;空串、带空白、缩写、单段或平台不支持的名称回答 `undefined`。 |
|
|
43
|
+
|
|
44
|
+
<a id="model-experience"></a>
|
|
45
|
+
## Model Experience
|
|
46
|
+
|
|
47
|
+
间接影响,取决于把规范时区记到持久消息上的那个消费方——`dsh-time-context` 据此渲染该轮模型可见的时区指令与时间戳。
|
|
48
|
+
|
|
49
|
+
#### KV Cache effect
|
|
50
|
+
|
|
51
|
+
自身没有。把时区派生文本注入请求的那个消费方,对该请求的缓存行为负责。
|
|
52
|
+
|
|
53
|
+
## Known Limitations and Deferred Work
|
|
54
|
+
|
|
55
|
+
<a id="known-limitations-and-deferred-work"></a>
|
|
56
|
+
|
|
57
|
+
- **别名解析取决于运行时的 ICU 数据**——一个别名组规范化成哪个名称由平台回答,因此两个跑在不同 Node 构建上的进程可能给出不同答案。
|
|
58
|
+
- **只做校验**——不格式化、不做偏移运算、不推导 DST、不做时刻换算;需要这些的消费方直接用 `Intl`。
|
|
59
|
+
|
|
60
|
+
<a id="dev-note"></a>
|
|
61
|
+
### 开发备注
|
|
62
|
+
|
|
63
|
+
<details>
|
|
64
|
+
<summary>维护者工作上下文——点击展开</summary>
|
|
65
|
+
|
|
66
|
+
无。
|
|
67
|
+
|
|
68
|
+
</details>
|
package/lib/index.js
ADDED
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
//#region lib/types/index.js
|
|
2
|
+
/**
|
|
3
|
+
* Time vocabulary shared by the wire boundaries that accept a caller's zone.
|
|
4
|
+
* Validation and canonicalization only: this library formats nothing and owns
|
|
5
|
+
* no failure vocabulary — each boundary declares and throws its own refusal.
|
|
6
|
+
* @module @deepseek-ai/dsh-util-time
|
|
7
|
+
*/
|
|
8
|
+
/** Strict browser-zone profile: UTC or an IANA Area/Location-style identifier. */
|
|
9
|
+
const IANA_TIME_ZONE = /^[A-Za-z][A-Za-z0-9_+.-]*(?:\/[A-Za-z0-9_+.-]+)+$/;
|
|
10
|
+
/**
|
|
11
|
+
* Validate and canonicalize one caller-supplied IANA zone at a wire boundary.
|
|
12
|
+
*
|
|
13
|
+
* The canonical name is what a later reader needs: a zone identity is stored on
|
|
14
|
+
* durable records and resolved again by another process, so an alias accepted
|
|
15
|
+
* here would not compare equal to the zone a reader derives.
|
|
16
|
+
* @param value - the caller's reported zone name.
|
|
17
|
+
* @returns the canonical zone, or `undefined` when the name is unusable.
|
|
18
|
+
*/
|
|
19
|
+
function canonicalClientTimeZone(value) {
|
|
20
|
+
if (value.length === 0 || value.trim() !== value || value !== "UTC" && !IANA_TIME_ZONE.test(value)) return void 0;
|
|
21
|
+
try {
|
|
22
|
+
const canonical = new Intl.DateTimeFormat("en-US", { timeZone: value }).resolvedOptions().timeZone;
|
|
23
|
+
/* v8 ignore next -- Intl returns UTC or a canonical IANA Area/Location for accepted input. */
|
|
24
|
+
if (canonical !== "UTC" && !IANA_TIME_ZONE.test(canonical)) return void 0;
|
|
25
|
+
return canonical;
|
|
26
|
+
} catch {
|
|
27
|
+
return;
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
//#endregion
|
|
31
|
+
export { canonicalClientTimeZone };
|
package/lib/invariant.js
ADDED
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
//#region lib/types/invariant.js
|
|
2
|
+
/**
|
|
3
|
+
* Package-owned invariant companion for `@deepseek-ai/dsh-util-time`.
|
|
4
|
+
* @module @deepseek-ai/dsh-util-time/invariant
|
|
5
|
+
*/
|
|
6
|
+
const PACKAGE_NAME = "@deepseek-ai/dsh-util-time";
|
|
7
|
+
/** Cordis companion plugin name. */
|
|
8
|
+
const name = "time-invariant";
|
|
9
|
+
/** Service required before the companion can reserve package ownership. */
|
|
10
|
+
const inject = ["invariants"];
|
|
11
|
+
/**
|
|
12
|
+
* No runtime invariant: this pure utility owns no event stream or mutable runtime data; its
|
|
13
|
+
* zone-canonicalization algebra is enforced by unit tests.
|
|
14
|
+
*/
|
|
15
|
+
const install = () => {};
|
|
16
|
+
/**
|
|
17
|
+
* Register this package's invariant companion.
|
|
18
|
+
* @param ctx - Cordis context carrying the invariant service.
|
|
19
|
+
* @returns the installed registration's disposer after setup succeeds.
|
|
20
|
+
*/
|
|
21
|
+
const apply = (ctx) => Promise.resolve(ctx.invariants.register(PACKAGE_NAME, install));
|
|
22
|
+
//#endregion
|
|
23
|
+
export { apply, inject, name };
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Time vocabulary shared by the wire boundaries that accept a caller's zone.
|
|
3
|
+
* Validation and canonicalization only: this library formats nothing and owns
|
|
4
|
+
* no failure vocabulary — each boundary declares and throws its own refusal.
|
|
5
|
+
* @module @deepseek-ai/dsh-util-time
|
|
6
|
+
*/
|
|
7
|
+
/**
|
|
8
|
+
* Validate and canonicalize one caller-supplied IANA zone at a wire boundary.
|
|
9
|
+
*
|
|
10
|
+
* The canonical name is what a later reader needs: a zone identity is stored on
|
|
11
|
+
* durable records and resolved again by another process, so an alias accepted
|
|
12
|
+
* here would not compare equal to the zone a reader derives.
|
|
13
|
+
* @param value - the caller's reported zone name.
|
|
14
|
+
* @returns the canonical zone, or `undefined` when the name is unusable.
|
|
15
|
+
*/
|
|
16
|
+
export declare function canonicalClientTimeZone(value: string): string | undefined;
|
|
17
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Package-owned invariant companion for `@deepseek-ai/dsh-util-time`.
|
|
3
|
+
* @module @deepseek-ai/dsh-util-time/invariant
|
|
4
|
+
*/
|
|
5
|
+
import type { Context } from '@deepseek-ai/cordis';
|
|
6
|
+
/** Cordis companion plugin name. */
|
|
7
|
+
export declare const name = "time-invariant";
|
|
8
|
+
/** Service required before the companion can reserve package ownership. */
|
|
9
|
+
export declare const inject: string[];
|
|
10
|
+
/**
|
|
11
|
+
* Register this package's invariant companion.
|
|
12
|
+
* @param ctx - Cordis context carrying the invariant service.
|
|
13
|
+
* @returns the installed registration's disposer after setup succeeds.
|
|
14
|
+
*/
|
|
15
|
+
export declare const apply: (ctx: Context) => Promise<() => void>;
|
|
16
|
+
//# sourceMappingURL=invariant.d.ts.map
|
package/package.json
ADDED
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@deepseek-ai/dsh-util-time",
|
|
3
|
+
"description": "Zero-dependency time vocabulary shared by wire boundaries: canonicalClientTimeZone (IANA zone validation and canonicalization only, no formatting)",
|
|
4
|
+
"version": "0.1.2-alpha.2",
|
|
5
|
+
"publishConfig": {
|
|
6
|
+
"access": "public"
|
|
7
|
+
},
|
|
8
|
+
"repository": {
|
|
9
|
+
"type": "git",
|
|
10
|
+
"url": "git+https://github.com/deepseek-ai/deepseek-harness.git",
|
|
11
|
+
"directory": "packages/util/time"
|
|
12
|
+
},
|
|
13
|
+
"type": "module",
|
|
14
|
+
"main": "lib/index.js",
|
|
15
|
+
"types": "lib/types/index.d.ts",
|
|
16
|
+
"exports": {
|
|
17
|
+
".": {
|
|
18
|
+
"types": "./lib/types/index.d.ts",
|
|
19
|
+
"default": "./lib/index.js"
|
|
20
|
+
},
|
|
21
|
+
"./invariant": {
|
|
22
|
+
"types": "./lib/types/invariant.d.ts",
|
|
23
|
+
"default": "./lib/invariant.js"
|
|
24
|
+
},
|
|
25
|
+
"./src/*": "./src/*",
|
|
26
|
+
"./package.json": "./package.json"
|
|
27
|
+
},
|
|
28
|
+
"files": [
|
|
29
|
+
"lib/index.js",
|
|
30
|
+
"lib/invariant.js",
|
|
31
|
+
"lib/types/**/*.d.ts"
|
|
32
|
+
],
|
|
33
|
+
"license": "MIT",
|
|
34
|
+
"peerDependencies": {
|
|
35
|
+
"@deepseek-ai/dsh-invariants": "^0.1.2-alpha.2",
|
|
36
|
+
"@deepseek-ai/cordis": "^4.0.2"
|
|
37
|
+
},
|
|
38
|
+
"devDependencies": {
|
|
39
|
+
"@deepseek-ai/cordis": "^4.0.2",
|
|
40
|
+
"@deepseek-ai/dsh-invariants": "^0.1.2-alpha.2"
|
|
41
|
+
}
|
|
42
|
+
}
|