@things-factory/shell 10.1.188 → 10.1.205

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.
@@ -0,0 +1,12 @@
1
+ /**
2
+ * **The calendar day in a timezone** - the one "today" of every module that keeps days (ADR-0120 decision 8).
3
+ *
4
+ * It lives here because the zone it reads is the domain's (`Domain.timezone`, `service/domain/domain.ts`): a site's day
5
+ * is a fact of the site, not of the module asking. It moved from `@things-factory/invoice` on 2026-10-20 when the
6
+ * warehouse needed a site's day for expiry (ADR-0076 ruling) - one function, one home, no second name.
7
+ *
8
+ * There is no default zone: a domain that names none would have its days moved silently in another country. The
9
+ * caller passes the zone its rule reads (a bank account's before its domain's); without one the person is told to set
10
+ * the domain's timezone.
11
+ */
12
+ export declare function calendarDay(timezone: string | null | undefined, now?: Date | number): string;
@@ -0,0 +1,21 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.calendarDay = calendarDay;
4
+ const refusal_js_1 = require("../refusal/refusal.js");
5
+ /**
6
+ * **The calendar day in a timezone** - the one "today" of every module that keeps days (ADR-0120 decision 8).
7
+ *
8
+ * It lives here because the zone it reads is the domain's (`Domain.timezone`, `service/domain/domain.ts`): a site's day
9
+ * is a fact of the site, not of the module asking. It moved from `@things-factory/invoice` on 2026-10-20 when the
10
+ * warehouse needed a site's day for expiry (ADR-0076 ruling) - one function, one home, no second name.
11
+ *
12
+ * There is no default zone: a domain that names none would have its days moved silently in another country. The
13
+ * caller passes the zone its rule reads (a bank account's before its domain's); without one the person is told to set
14
+ * the domain's timezone.
15
+ */
16
+ function calendarDay(timezone, now = new Date()) {
17
+ if (!timezone)
18
+ throw new refusal_js_1.Refusal('timezone-required', {}, "Set the domain's timezone in domain management");
19
+ return new Intl.DateTimeFormat('en-CA', { timeZone: timezone, year: 'numeric', month: '2-digit', day: '2-digit' }).format(now);
20
+ }
21
+ //# sourceMappingURL=calendar-day.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"calendar-day.js","sourceRoot":"","sources":["../../server/utils/calendar-day.ts"],"names":[],"mappings":";;AAaA,kCAGC;AAhBD,sDAA+C;AAE/C;;;;;;;;;;GAUG;AACH,SAAgB,WAAW,CAAC,QAAmC,EAAE,MAAqB,IAAI,IAAI,EAAE;IAC9F,IAAI,CAAC,QAAQ;QAAE,MAAM,IAAI,oBAAO,CAAC,mBAAmB,EAAE,EAAE,EAAE,gDAAgD,CAAC,CAAA;IAC3G,OAAO,IAAI,IAAI,CAAC,cAAc,CAAC,OAAO,EAAE,EAAE,QAAQ,EAAE,QAAQ,EAAE,IAAI,EAAE,SAAS,EAAE,KAAK,EAAE,SAAS,EAAE,GAAG,EAAE,SAAS,EAAE,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,CAAA;AAChI,CAAC","sourcesContent":["import { Refusal } from '../refusal/refusal.js'\n\n/**\n * **The calendar day in a timezone** - the one \"today\" of every module that keeps days (ADR-0120 decision 8).\n *\n * It lives here because the zone it reads is the domain's (`Domain.timezone`, `service/domain/domain.ts`): a site's day\n * is a fact of the site, not of the module asking. It moved from `@things-factory/invoice` on 2026-10-20 when the\n * warehouse needed a site's day for expiry (ADR-0076 ruling) - one function, one home, no second name.\n *\n * There is no default zone: a domain that names none would have its days moved silently in another country. The\n * caller passes the zone its rule reads (a bank account's before its domain's); without one the person is told to set\n * the domain's timezone.\n */\nexport function calendarDay(timezone: string | null | undefined, now: Date | number = new Date()): string {\n if (!timezone) throw new Refusal('timezone-required', {}, \"Set the domain's timezone in domain management\")\n return new Intl.DateTimeFormat('en-CA', { timeZone: timezone, year: 'numeric', month: '2-digit', day: '2-digit' }).format(now)\n}\n"]}
@@ -13,3 +13,4 @@ export * from './subscribe-auth.js';
13
13
  export * from './after-commit.js';
14
14
  export * from './domain-ancestry.js';
15
15
  export * from './secret-hint.js';
16
+ export * from './calendar-day.js';
@@ -16,4 +16,5 @@ tslib_1.__exportStar(require("./subscribe-auth.js"), exports);
16
16
  tslib_1.__exportStar(require("./after-commit.js"), exports);
17
17
  tslib_1.__exportStar(require("./domain-ancestry.js"), exports);
18
18
  tslib_1.__exportStar(require("./secret-hint.js"), exports);
19
+ tslib_1.__exportStar(require("./calendar-day.js"), exports);
19
20
  //# sourceMappingURL=index.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../../server/utils/index.ts"],"names":[],"mappings":";;;AAAA,0DAA+B;AAC/B,mEAAwC;AACxC,iEAAsC;AACtC,kEAAuC;AACvC,qEAA0C;AAC1C,gEAAqC;AACrC,kFAAuD;AACvD,6DAAkC;AAClC,mEAAwC;AACxC,oEAAyC;AACzC,mEAAwC;AACxC,8DAAmC;AACnC,4DAAiC;AACjC,+DAAoC;AACpC,2DAAgC","sourcesContent":["export * from './get-domain.js'\nexport * from './apply-domain-filter.js'\nexport * from './condition-builder.js'\nexport * from './list-query-builder.js'\nexport * from './list-params-converter.js'\nexport * from './publish-progress.js'\nexport * from './get-query-builder-from-list-params.js'\nexport * from './keyset-cursor.js'\nexport * from './list-param-adjuster.js'\nexport * from './get-times-for-period.js'\nexport * from './headless-pool/index.js'\nexport * from './subscribe-auth.js'\nexport * from './after-commit.js'\nexport * from './domain-ancestry.js'\nexport * from './secret-hint.js'\n"]}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../server/utils/index.ts"],"names":[],"mappings":";;;AAAA,0DAA+B;AAC/B,mEAAwC;AACxC,iEAAsC;AACtC,kEAAuC;AACvC,qEAA0C;AAC1C,gEAAqC;AACrC,kFAAuD;AACvD,6DAAkC;AAClC,mEAAwC;AACxC,oEAAyC;AACzC,mEAAwC;AACxC,8DAAmC;AACnC,4DAAiC;AACjC,+DAAoC;AACpC,2DAAgC;AAChC,4DAAiC","sourcesContent":["export * from './get-domain.js'\nexport * from './apply-domain-filter.js'\nexport * from './condition-builder.js'\nexport * from './list-query-builder.js'\nexport * from './list-params-converter.js'\nexport * from './publish-progress.js'\nexport * from './get-query-builder-from-list-params.js'\nexport * from './keyset-cursor.js'\nexport * from './list-param-adjuster.js'\nexport * from './get-times-for-period.js'\nexport * from './headless-pool/index.js'\nexport * from './subscribe-auth.js'\nexport * from './after-commit.js'\nexport * from './domain-ancestry.js'\nexport * from './secret-hint.js'\nexport * from './calendar-day.js'\n"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@things-factory/shell",
3
- "version": "10.1.188",
3
+ "version": "10.1.205",
4
4
  "description": "Core module for framework",
5
5
  "bin": {
6
6
  "things-factory": "bin/things-factory",
@@ -142,5 +142,5 @@
142
142
  "pg": "^8.7.3",
143
143
  "sqlite3": "^5.0.8"
144
144
  },
145
- "gitHead": "c5e75e2e0b565e0666472bc835f5f1538fb18f48"
145
+ "gitHead": "7311492aa5eaa00993c0325053f5f7ae8b1fb024"
146
146
  }
@@ -0,0 +1,21 @@
1
+ import { calendarDay } from '../server/utils/calendar-day'
2
+
3
+ /**
4
+ * A site's day (ADR-0120 decision 8). One instant is a different day in different zones, and a domain without a zone
5
+ * is told to set one - never moved to the server's day. Moved from `@things-factory/invoice` with the function.
6
+ */
7
+ describe('calendarDay', () => {
8
+ const at = new Date('2026-12-31T20:00:00Z')
9
+
10
+ it('is the day in the zone it is given, not the server clock\'s', () => {
11
+ expect(calendarDay('Asia/Seoul', at)).toBe('2027-01-01')
12
+ expect(calendarDay('UTC', at)).toBe('2026-12-31')
13
+ expect(calendarDay('America/Los_Angeles', at.getTime())).toBe('2026-12-31')
14
+ })
15
+
16
+ it('refuses a missing zone by name instead of falling back to one', () => {
17
+ for (const none of ['', undefined, null]) {
18
+ expect(() => calendarDay(none as any, at)).toThrow(expect.objectContaining({ code: 'timezone-required' }))
19
+ }
20
+ })
21
+ })
@@ -185,5 +185,6 @@
185
185
  "button.resume-editing": "resume editing",
186
186
  "button.discard": "discard",
187
187
  "figure.label.motion": "Motion",
188
- "figure.text.preview-needs-a-part": "add a part to see how it looks placed on a drawing."
188
+ "figure.text.preview-needs-a-part": "add a part to see how it looks placed on a drawing.",
189
+ "error.timezone-required": "The $t(term.domain) has no timezone. Set it in $t(term.domain) management."
189
190
  }
@@ -185,5 +185,6 @@
185
185
  "button.resume-editing": "reanudar edición",
186
186
  "button.discard": "descartar",
187
187
  "figure.label.motion": "Movimiento",
188
- "figure.text.preview-needs-a-part": "añada una pieza para ver cómo se ve colocada en un plano."
188
+ "figure.text.preview-needs-a-part": "añada una pieza para ver cómo se ve colocada en un plano.",
189
+ "error.timezone-required": "El dominio no tiene zona horaria. Configúrela en la gestión de dominios."
189
190
  }
@@ -185,5 +185,6 @@
185
185
  "button.resume-editing": "編集を続ける",
186
186
  "button.discard": "破棄",
187
187
  "figure.label.motion": "Motion",
188
- "figure.text.preview-needs-a-part": "部品を追加すると、図面に置いたときの姿が表示されます。"
188
+ "figure.text.preview-needs-a-part": "部品を追加すると、図面に置いたときの姿が表示されます。",
189
+ "error.timezone-required": "事業所のタイムゾーンが設定されていません。事業所管理でタイムゾーンを設定してください。"
189
190
  }
@@ -185,5 +185,6 @@
185
185
  "button.resume-editing": "이어서 편집",
186
186
  "button.discard": "버리기",
187
187
  "figure.label.motion": "움직임",
188
- "figure.text.preview-needs-a-part": "부품을 추가하면 도면에 놓았을 때의 모습이 표시됩니다."
188
+ "figure.text.preview-needs-a-part": "부품을 추가하면 도면에 놓았을 때의 모습이 표시됩니다.",
189
+ "error.timezone-required": "$t(term.domain) 시간대가 정해지지 않았습니다. $t(term.domain) 관리에서 시간대를 정하세요."
189
190
  }
@@ -185,5 +185,6 @@
185
185
  "button.resume-editing": "sambung menyunting",
186
186
  "button.discard": "buang",
187
187
  "figure.label.motion": "Motion",
188
- "figure.text.preview-needs-a-part": "tambah bahagian untuk melihat rupanya apabila diletakkan pada lukisan."
188
+ "figure.text.preview-needs-a-part": "tambah bahagian untuk melihat rupanya apabila diletakkan pada lukisan.",
189
+ "error.timezone-required": "Domain tiada zon waktu. Tetapkannya dalam pengurusan domain."
189
190
  }
@@ -185,5 +185,6 @@
185
185
  "button.resume-editing": "继续编辑",
186
186
  "button.discard": "放弃",
187
187
  "figure.label.motion": "Motion",
188
- "figure.text.preview-needs-a-part": "添加部件后会显示放置到图面上的效果。"
188
+ "figure.text.preview-needs-a-part": "添加部件后会显示放置到图面上的效果。",
189
+ "error.timezone-required": "尚未设置单位时区。请在单位管理中设置时区。"
189
190
  }