fieldsmith 0.1.0

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.
Files changed (47) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +843 -0
  3. package/assets/fonts/DotGothic16.ttf +0 -0
  4. package/assets/fonts/OFL.txt +93 -0
  5. package/dist/cli/exit.js +37 -0
  6. package/dist/cli/exit.js.map +1 -0
  7. package/dist/cli/index.js +699 -0
  8. package/dist/cli/index.js.map +1 -0
  9. package/dist/cli/output.js +61 -0
  10. package/dist/cli/output.js.map +1 -0
  11. package/dist/cli/progress.js +83 -0
  12. package/dist/cli/progress.js.map +1 -0
  13. package/dist/cli/promptInput.js +57 -0
  14. package/dist/cli/promptInput.js.map +1 -0
  15. package/dist/cli/schema.js +140 -0
  16. package/dist/cli/schema.js.map +1 -0
  17. package/dist/config.js +149 -0
  18. package/dist/config.js.map +1 -0
  19. package/dist/icon/emojiFont.js +163 -0
  20. package/dist/icon/emojiFont.js.map +1 -0
  21. package/dist/icon/render.js +136 -0
  22. package/dist/icon/render.js.map +1 -0
  23. package/dist/kintone/client.js +157 -0
  24. package/dist/kintone/client.js.map +1 -0
  25. package/dist/kintone/deploy.js +519 -0
  26. package/dist/kintone/deploy.js.map +1 -0
  27. package/dist/kintone/oauth.js +156 -0
  28. package/dist/kintone/oauth.js.map +1 -0
  29. package/dist/kintone/tokenStore.js +87 -0
  30. package/dist/kintone/tokenStore.js.map +1 -0
  31. package/dist/llm/generate.js +317 -0
  32. package/dist/llm/generate.js.map +1 -0
  33. package/dist/llm/prompt.js +142 -0
  34. package/dist/llm/prompt.js.map +1 -0
  35. package/dist/spec/appSpec.js +283 -0
  36. package/dist/spec/appSpec.js.map +1 -0
  37. package/dist/spec/diff.js +218 -0
  38. package/dist/spec/diff.js.map +1 -0
  39. package/dist/spec/fieldSpec.js +353 -0
  40. package/dist/spec/fieldSpec.js.map +1 -0
  41. package/dist/spec/fromKintone.js +230 -0
  42. package/dist/spec/fromKintone.js.map +1 -0
  43. package/dist/spec/layout.js +215 -0
  44. package/dist/spec/layout.js.map +1 -0
  45. package/dist/spec/toKintone.js +170 -0
  46. package/dist/spec/toKintone.js.map +1 -0
  47. package/package.json +59 -0
@@ -0,0 +1,163 @@
1
+ import { existsSync, readFileSync } from "node:fs";
2
+ import { homedir } from "node:os";
3
+ import { join } from "node:path";
4
+ /**
5
+ * Noto Color Emoji から絵文字のビットマップを取り出す。
6
+ *
7
+ * なぜこんなことをするのか:
8
+ * Noto Color Emoji は CBDT/CBLC 形式のビットマップフォントで、絵文字の実体は
9
+ * フォント内に埋め込まれた PNG そのもの。一方 resvg はこの形式を描画できず、
10
+ * `<text>` に絵文字を置いても空白になる。
11
+ * ラスタライズは不要で、埋め込まれた PNG をそのまま取り出せば済むため、
12
+ * ここで CBDT を直接読んでいる。
13
+ *
14
+ * @see https://learn.microsoft.com/en-us/typography/opentype/spec/cbdt
15
+ */
16
+ /** 絵文字フォントの探索先。fontconfig に頼らず、よくある場所を順に見る。 */
17
+ const FONT_CANDIDATES = [
18
+ join(homedir(), ".fonts", "NotoColorEmoji.ttf"),
19
+ join(homedir(), ".local", "share", "fonts", "NotoColorEmoji.ttf"),
20
+ "/usr/share/fonts/truetype/noto/NotoColorEmoji.ttf",
21
+ "/usr/share/fonts/opentype/noto/NotoColorEmoji.ttf",
22
+ "/usr/local/share/fonts/NotoColorEmoji.ttf",
23
+ "/System/Library/Fonts/Apple Color Emoji.ttc",
24
+ ];
25
+ export class EmojiFontError extends Error {
26
+ constructor(message) {
27
+ super(message);
28
+ this.name = "EmojiFontError";
29
+ }
30
+ }
31
+ /** 絵文字フォントのパスを返す。見つからなければ null。 */
32
+ export function findEmojiFont(candidates = FONT_CANDIDATES) {
33
+ return candidates.find((path) => existsSync(path)) ?? null;
34
+ }
35
+ function readTables(font) {
36
+ const numTables = font.readUInt16BE(4);
37
+ const tables = {};
38
+ for (let i = 0; i < numTables; i += 1) {
39
+ const record = 12 + i * 16;
40
+ const tag = font.toString("latin1", record, record + 4);
41
+ tables[tag] = { offset: font.readUInt32BE(record + 8), length: font.readUInt32BE(record + 12) };
42
+ }
43
+ return tables;
44
+ }
45
+ /**
46
+ * cmap のサブテーブル (format 4 / 12) から符号位置に対応するグリフ ID を引く。
47
+ * 絵文字は BMP 外なので format 12 が本命だが、念のため format 4 も見る。
48
+ */
49
+ function lookupGlyphId(font, cmapOffset, codePoint) {
50
+ const numTables = font.readUInt16BE(cmapOffset + 2);
51
+ let format12 = null;
52
+ let format4 = null;
53
+ for (let i = 0; i < numTables; i += 1) {
54
+ const record = cmapOffset + 4 + i * 8;
55
+ const subtable = cmapOffset + font.readUInt32BE(record + 4);
56
+ const format = font.readUInt16BE(subtable);
57
+ if (format === 12)
58
+ format12 = subtable;
59
+ else if (format === 4 && format4 === null)
60
+ format4 = subtable;
61
+ }
62
+ if (format12 !== null) {
63
+ const numGroups = font.readUInt32BE(format12 + 12);
64
+ for (let i = 0; i < numGroups; i += 1) {
65
+ const group = format12 + 16 + i * 12;
66
+ const start = font.readUInt32BE(group);
67
+ const end = font.readUInt32BE(group + 4);
68
+ if (codePoint >= start && codePoint <= end) {
69
+ return font.readUInt32BE(group + 8) + (codePoint - start);
70
+ }
71
+ }
72
+ }
73
+ if (format4 !== null && codePoint <= 0xffff) {
74
+ const segCountX2 = font.readUInt16BE(format4 + 6);
75
+ const endCodes = format4 + 14;
76
+ const startCodes = endCodes + segCountX2 + 2;
77
+ const idDeltas = startCodes + segCountX2;
78
+ const idRangeOffsets = idDeltas + segCountX2;
79
+ for (let i = 0; i < segCountX2 / 2; i += 1) {
80
+ if (codePoint > font.readUInt16BE(endCodes + i * 2))
81
+ continue;
82
+ const start = font.readUInt16BE(startCodes + i * 2);
83
+ if (codePoint < start)
84
+ return 0;
85
+ const rangeOffset = font.readUInt16BE(idRangeOffsets + i * 2);
86
+ if (rangeOffset === 0) {
87
+ return (codePoint + font.readInt16BE(idDeltas + i * 2)) & 0xffff;
88
+ }
89
+ const glyphAddress = idRangeOffsets + i * 2 + rangeOffset + (codePoint - start) * 2;
90
+ const glyph = font.readUInt16BE(glyphAddress);
91
+ return glyph === 0 ? 0 : (glyph + font.readInt16BE(idDeltas + i * 2)) & 0xffff;
92
+ }
93
+ }
94
+ return 0;
95
+ }
96
+ /** CBLC を辿って、そのグリフの画像データが CBDT のどこにあるかを求める。 */
97
+ function locateBitmap(font, cblc, cbdt, glyphId) {
98
+ const numSizes = font.readUInt32BE(cblc + 4);
99
+ for (let size = 0; size < numSizes; size += 1) {
100
+ // bitmapSize レコードは 48 バイト。先頭が indexSubTableArray への相対オフセット。
101
+ const record = cblc + 8 + size * 48;
102
+ const arrayOffset = font.readUInt32BE(record);
103
+ const numSubTables = font.readUInt32BE(record + 8);
104
+ for (let i = 0; i < numSubTables; i += 1) {
105
+ const entry = cblc + arrayOffset + i * 8;
106
+ const firstGlyph = font.readUInt16BE(entry);
107
+ const lastGlyph = font.readUInt16BE(entry + 2);
108
+ if (glyphId < firstGlyph || glyphId > lastGlyph)
109
+ continue;
110
+ const subTable = cblc + arrayOffset + font.readUInt32BE(entry + 4);
111
+ const indexFormat = font.readUInt16BE(subTable);
112
+ const imageFormat = font.readUInt16BE(subTable + 2);
113
+ const imageDataOffset = font.readUInt32BE(subTable + 4);
114
+ // indexFormat 1 は 4 バイトのオフセット配列。Noto Color Emoji はこれ。
115
+ if (indexFormat !== 1)
116
+ continue;
117
+ const index = glyphId - firstGlyph;
118
+ const start = font.readUInt32BE(subTable + 8 + index * 4);
119
+ const end = font.readUInt32BE(subTable + 8 + index * 4 + 4);
120
+ if (end <= start)
121
+ return null;
122
+ return { offset: cbdt + imageDataOffset + start, imageFormat };
123
+ }
124
+ }
125
+ return null;
126
+ }
127
+ /**
128
+ * 符号位置に対応する絵文字の PNG を取り出す。該当が無ければ null。
129
+ *
130
+ * 異体字セレクタ (U+FE0F) や肌の色などを含む複数符号位置の絵文字 (ZWJ 連結、国旗) は
131
+ * GSUB による合字で表現されており、ここでは解決できない。呼び出し側で先頭の
132
+ * 符号位置に落として扱う。
133
+ */
134
+ export function extractEmojiPng(fontPath, codePoint) {
135
+ const font = readFileSync(fontPath);
136
+ const tables = readTables(font);
137
+ const cmap = tables["cmap"];
138
+ const cblc = tables["CBLC"];
139
+ const cbdt = tables["CBDT"];
140
+ if (cmap === undefined || cblc === undefined || cbdt === undefined) {
141
+ throw new EmojiFontError(`${fontPath} は CBDT 形式のビットマップ絵文字フォントではありません (CBDT/CBLC/cmap が見つかりません)。`);
142
+ }
143
+ const glyphId = lookupGlyphId(font, cmap.offset, codePoint);
144
+ if (glyphId === 0)
145
+ return null;
146
+ const located = locateBitmap(font, cblc.offset, cbdt.offset, glyphId);
147
+ if (located === null)
148
+ return null;
149
+ // imageFormat 17: smallGlyphMetrics (5 バイト) + データ長 (4 バイト) + PNG
150
+ // imageFormat 18: bigGlyphMetrics (8 バイト) + データ長 (4 バイト) + PNG
151
+ const headerSize = located.imageFormat === 18 ? 8 : located.imageFormat === 17 ? 5 : -1;
152
+ if (headerSize < 0)
153
+ return null;
154
+ const lengthAt = located.offset + headerSize;
155
+ const dataLength = font.readUInt32BE(lengthAt);
156
+ const png = font.subarray(lengthAt + 4, lengthAt + 4 + dataLength);
157
+ // 取り出したものが本当に PNG かを確かめる (テーブルの読み違いを黙って通さない)。
158
+ const signature = Buffer.from([0x89, 0x50, 0x4e, 0x47, 0x0d, 0x0a, 0x1a, 0x0a]);
159
+ if (!png.subarray(0, 8).equals(signature))
160
+ return null;
161
+ return Buffer.from(png);
162
+ }
163
+ //# sourceMappingURL=emojiFont.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"emojiFont.js","sourceRoot":"","sources":["../../src/icon/emojiFont.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AACnD,OAAO,EAAE,OAAO,EAAE,MAAM,SAAS,CAAC;AAClC,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AAEjC;;;;;;;;;;;GAWG;AAEH,+CAA+C;AAC/C,MAAM,eAAe,GAAG;IACtB,IAAI,CAAC,OAAO,EAAE,EAAE,QAAQ,EAAE,oBAAoB,CAAC;IAC/C,IAAI,CAAC,OAAO,EAAE,EAAE,QAAQ,EAAE,OAAO,EAAE,OAAO,EAAE,oBAAoB,CAAC;IACjE,mDAAmD;IACnD,mDAAmD;IACnD,2CAA2C;IAC3C,6CAA6C;CAC9C,CAAC;AAEF,MAAM,OAAO,cAAe,SAAQ,KAAK;IACvC,YAAY,OAAe;QACzB,KAAK,CAAC,OAAO,CAAC,CAAC;QACf,IAAI,CAAC,IAAI,GAAG,gBAAgB,CAAC;IAC/B,CAAC;CACF;AAED,mCAAmC;AACnC,MAAM,UAAU,aAAa,CAAC,aAAgC,eAAe;IAC3E,OAAO,UAAU,CAAC,IAAI,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,UAAU,CAAC,IAAI,CAAC,CAAC,IAAI,IAAI,CAAC;AAC7D,CAAC;AAMD,SAAS,UAAU,CAAC,IAAY;IAC9B,MAAM,SAAS,GAAG,IAAI,CAAC,YAAY,CAAC,CAAC,CAAC,CAAC;IACvC,MAAM,MAAM,GAAuD,EAAE,CAAC;IACtE,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,SAAS,EAAE,CAAC,IAAI,CAAC,EAAE,CAAC;QACtC,MAAM,MAAM,GAAG,EAAE,GAAG,CAAC,GAAG,EAAE,CAAC;QAC3B,MAAM,GAAG,GAAG,IAAI,CAAC,QAAQ,CAAC,QAAQ,EAAE,MAAM,EAAE,MAAM,GAAG,CAAC,CAAC,CAAC;QACxD,MAAM,CAAC,GAAG,CAAC,GAAG,EAAE,MAAM,EAAE,IAAI,CAAC,YAAY,CAAC,MAAM,GAAG,CAAC,CAAC,EAAE,MAAM,EAAE,IAAI,CAAC,YAAY,CAAC,MAAM,GAAG,EAAE,CAAC,EAAE,CAAC;IAClG,CAAC;IACD,OAAO,MAAM,CAAC;AAChB,CAAC;AAED;;;GAGG;AACH,SAAS,aAAa,CAAC,IAAY,EAAE,UAAkB,EAAE,SAAiB;IACxE,MAAM,SAAS,GAAG,IAAI,CAAC,YAAY,CAAC,UAAU,GAAG,CAAC,CAAC,CAAC;IACpD,IAAI,QAAQ,GAAkB,IAAI,CAAC;IACnC,IAAI,OAAO,GAAkB,IAAI,CAAC;IAElC,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,SAAS,EAAE,CAAC,IAAI,CAAC,EAAE,CAAC;QACtC,MAAM,MAAM,GAAG,UAAU,GAAG,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;QACtC,MAAM,QAAQ,GAAG,UAAU,GAAG,IAAI,CAAC,YAAY,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC;QAC5D,MAAM,MAAM,GAAG,IAAI,CAAC,YAAY,CAAC,QAAQ,CAAC,CAAC;QAC3C,IAAI,MAAM,KAAK,EAAE;YAAE,QAAQ,GAAG,QAAQ,CAAC;aAClC,IAAI,MAAM,KAAK,CAAC,IAAI,OAAO,KAAK,IAAI;YAAE,OAAO,GAAG,QAAQ,CAAC;IAChE,CAAC;IAED,IAAI,QAAQ,KAAK,IAAI,EAAE,CAAC;QACtB,MAAM,SAAS,GAAG,IAAI,CAAC,YAAY,CAAC,QAAQ,GAAG,EAAE,CAAC,CAAC;QACnD,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,SAAS,EAAE,CAAC,IAAI,CAAC,EAAE,CAAC;YACtC,MAAM,KAAK,GAAG,QAAQ,GAAG,EAAE,GAAG,CAAC,GAAG,EAAE,CAAC;YACrC,MAAM,KAAK,GAAG,IAAI,CAAC,YAAY,CAAC,KAAK,CAAC,CAAC;YACvC,MAAM,GAAG,GAAG,IAAI,CAAC,YAAY,CAAC,KAAK,GAAG,CAAC,CAAC,CAAC;YACzC,IAAI,SAAS,IAAI,KAAK,IAAI,SAAS,IAAI,GAAG,EAAE,CAAC;gBAC3C,OAAO,IAAI,CAAC,YAAY,CAAC,KAAK,GAAG,CAAC,CAAC,GAAG,CAAC,SAAS,GAAG,KAAK,CAAC,CAAC;YAC5D,CAAC;QACH,CAAC;IACH,CAAC;IAED,IAAI,OAAO,KAAK,IAAI,IAAI,SAAS,IAAI,MAAM,EAAE,CAAC;QAC5C,MAAM,UAAU,GAAG,IAAI,CAAC,YAAY,CAAC,OAAO,GAAG,CAAC,CAAC,CAAC;QAClD,MAAM,QAAQ,GAAG,OAAO,GAAG,EAAE,CAAC;QAC9B,MAAM,UAAU,GAAG,QAAQ,GAAG,UAAU,GAAG,CAAC,CAAC;QAC7C,MAAM,QAAQ,GAAG,UAAU,GAAG,UAAU,CAAC;QACzC,MAAM,cAAc,GAAG,QAAQ,GAAG,UAAU,CAAC;QAE7C,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,UAAU,GAAG,CAAC,EAAE,CAAC,IAAI,CAAC,EAAE,CAAC;YAC3C,IAAI,SAAS,GAAG,IAAI,CAAC,YAAY,CAAC,QAAQ,GAAG,CAAC,GAAG,CAAC,CAAC;gBAAE,SAAS;YAC9D,MAAM,KAAK,GAAG,IAAI,CAAC,YAAY,CAAC,UAAU,GAAG,CAAC,GAAG,CAAC,CAAC,CAAC;YACpD,IAAI,SAAS,GAAG,KAAK;gBAAE,OAAO,CAAC,CAAC;YAEhC,MAAM,WAAW,GAAG,IAAI,CAAC,YAAY,CAAC,cAAc,GAAG,CAAC,GAAG,CAAC,CAAC,CAAC;YAC9D,IAAI,WAAW,KAAK,CAAC,EAAE,CAAC;gBACtB,OAAO,CAAC,SAAS,GAAG,IAAI,CAAC,WAAW,CAAC,QAAQ,GAAG,CAAC,GAAG,CAAC,CAAC,CAAC,GAAG,MAAM,CAAC;YACnE,CAAC;YACD,MAAM,YAAY,GAAG,cAAc,GAAG,CAAC,GAAG,CAAC,GAAG,WAAW,GAAG,CAAC,SAAS,GAAG,KAAK,CAAC,GAAG,CAAC,CAAC;YACpF,MAAM,KAAK,GAAG,IAAI,CAAC,YAAY,CAAC,YAAY,CAAC,CAAC;YAC9C,OAAO,KAAK,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,KAAK,GAAG,IAAI,CAAC,WAAW,CAAC,QAAQ,GAAG,CAAC,GAAG,CAAC,CAAC,CAAC,GAAG,MAAM,CAAC;QACjF,CAAC;IACH,CAAC;IAED,OAAO,CAAC,CAAC;AACX,CAAC;AAED,+CAA+C;AAC/C,SAAS,YAAY,CACnB,IAAY,EACZ,IAAY,EACZ,IAAY,EACZ,OAAe;IAEf,MAAM,QAAQ,GAAG,IAAI,CAAC,YAAY,CAAC,IAAI,GAAG,CAAC,CAAC,CAAC;IAE7C,KAAK,IAAI,IAAI,GAAG,CAAC,EAAE,IAAI,GAAG,QAAQ,EAAE,IAAI,IAAI,CAAC,EAAE,CAAC;QAC9C,4DAA4D;QAC5D,MAAM,MAAM,GAAG,IAAI,GAAG,CAAC,GAAG,IAAI,GAAG,EAAE,CAAC;QACpC,MAAM,WAAW,GAAG,IAAI,CAAC,YAAY,CAAC,MAAM,CAAC,CAAC;QAC9C,MAAM,YAAY,GAAG,IAAI,CAAC,YAAY,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC;QAEnD,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,YAAY,EAAE,CAAC,IAAI,CAAC,EAAE,CAAC;YACzC,MAAM,KAAK,GAAG,IAAI,GAAG,WAAW,GAAG,CAAC,GAAG,CAAC,CAAC;YACzC,MAAM,UAAU,GAAG,IAAI,CAAC,YAAY,CAAC,KAAK,CAAC,CAAC;YAC5C,MAAM,SAAS,GAAG,IAAI,CAAC,YAAY,CAAC,KAAK,GAAG,CAAC,CAAC,CAAC;YAC/C,IAAI,OAAO,GAAG,UAAU,IAAI,OAAO,GAAG,SAAS;gBAAE,SAAS;YAE1D,MAAM,QAAQ,GAAG,IAAI,GAAG,WAAW,GAAG,IAAI,CAAC,YAAY,CAAC,KAAK,GAAG,CAAC,CAAC,CAAC;YACnE,MAAM,WAAW,GAAG,IAAI,CAAC,YAAY,CAAC,QAAQ,CAAC,CAAC;YAChD,MAAM,WAAW,GAAG,IAAI,CAAC,YAAY,CAAC,QAAQ,GAAG,CAAC,CAAC,CAAC;YACpD,MAAM,eAAe,GAAG,IAAI,CAAC,YAAY,CAAC,QAAQ,GAAG,CAAC,CAAC,CAAC;YAExD,sDAAsD;YACtD,IAAI,WAAW,KAAK,CAAC;gBAAE,SAAS;YAChC,MAAM,KAAK,GAAG,OAAO,GAAG,UAAU,CAAC;YACnC,MAAM,KAAK,GAAG,IAAI,CAAC,YAAY,CAAC,QAAQ,GAAG,CAAC,GAAG,KAAK,GAAG,CAAC,CAAC,CAAC;YAC1D,MAAM,GAAG,GAAG,IAAI,CAAC,YAAY,CAAC,QAAQ,GAAG,CAAC,GAAG,KAAK,GAAG,CAAC,GAAG,CAAC,CAAC,CAAC;YAC5D,IAAI,GAAG,IAAI,KAAK;gBAAE,OAAO,IAAI,CAAC;YAE9B,OAAO,EAAE,MAAM,EAAE,IAAI,GAAG,eAAe,GAAG,KAAK,EAAE,WAAW,EAAE,CAAC;QACjE,CAAC;IACH,CAAC;IACD,OAAO,IAAI,CAAC;AACd,CAAC;AAED;;;;;;GAMG;AACH,MAAM,UAAU,eAAe,CAAC,QAAgB,EAAE,SAAiB;IACjE,MAAM,IAAI,GAAG,YAAY,CAAC,QAAQ,CAAC,CAAC;IACpC,MAAM,MAAM,GAAG,UAAU,CAAC,IAAI,CAAC,CAAC;IAEhC,MAAM,IAAI,GAAG,MAAM,CAAC,MAAM,CAAC,CAAC;IAC5B,MAAM,IAAI,GAAG,MAAM,CAAC,MAAM,CAAC,CAAC;IAC5B,MAAM,IAAI,GAAG,MAAM,CAAC,MAAM,CAAC,CAAC;IAC5B,IAAI,IAAI,KAAK,SAAS,IAAI,IAAI,KAAK,SAAS,IAAI,IAAI,KAAK,SAAS,EAAE,CAAC;QACnE,MAAM,IAAI,cAAc,CACtB,GAAG,QAAQ,4DAA4D,CACxE,CAAC;IACJ,CAAC;IAED,MAAM,OAAO,GAAG,aAAa,CAAC,IAAI,EAAE,IAAI,CAAC,MAAM,EAAE,SAAS,CAAC,CAAC;IAC5D,IAAI,OAAO,KAAK,CAAC;QAAE,OAAO,IAAI,CAAC;IAE/B,MAAM,OAAO,GAAG,YAAY,CAAC,IAAI,EAAE,IAAI,CAAC,MAAM,EAAE,IAAI,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IACtE,IAAI,OAAO,KAAK,IAAI;QAAE,OAAO,IAAI,CAAC;IAElC,iEAAiE;IACjE,+DAA+D;IAC/D,MAAM,UAAU,GAAG,OAAO,CAAC,WAAW,KAAK,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,WAAW,KAAK,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;IACxF,IAAI,UAAU,GAAG,CAAC;QAAE,OAAO,IAAI,CAAC;IAEhC,MAAM,QAAQ,GAAG,OAAO,CAAC,MAAM,GAAG,UAAU,CAAC;IAC7C,MAAM,UAAU,GAAG,IAAI,CAAC,YAAY,CAAC,QAAQ,CAAC,CAAC;IAC/C,MAAM,GAAG,GAAG,IAAI,CAAC,QAAQ,CAAC,QAAQ,GAAG,CAAC,EAAE,QAAQ,GAAG,CAAC,GAAG,UAAU,CAAC,CAAC;IAEnE,8CAA8C;IAC9C,MAAM,SAAS,GAAG,MAAM,CAAC,IAAI,CAAC,CAAC,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,CAAC,CAAC,CAAC;IAChF,IAAI,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,MAAM,CAAC,SAAS,CAAC;QAAE,OAAO,IAAI,CAAC;IAEvD,OAAO,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;AAC1B,CAAC"}
@@ -0,0 +1,136 @@
1
+ import { existsSync } from "node:fs";
2
+ import { dirname, join } from "node:path";
3
+ import { fileURLToPath } from "node:url";
4
+ import { Resvg } from "@resvg/resvg-js";
5
+ import { extractEmojiPng, findEmojiFont } from "./emojiFont.js";
6
+ /** 生成するアイコンの一辺 (px)。kintone の表示に対して十分な解像度。 */
7
+ export const ICON_SIZE = 256;
8
+ /** kintone がアプリアイコンとして受け付けるファイルサイズの上限。 */
9
+ export const MAX_ICON_BYTES = 800 * 1024;
10
+ /** 同梱している DotGothic16 のパス。ドット絵風の日本語フォント (OFL-1.1)。 */
11
+ export function bundledFontPath() {
12
+ // dist/icon/render.js からも src/icon/render.ts からも同じ assets を指すよう遡る。
13
+ const here = dirname(fileURLToPath(import.meta.url));
14
+ for (const candidate of [
15
+ join(here, "..", "..", "assets", "fonts", "DotGothic16.ttf"),
16
+ join(here, "..", "..", "..", "assets", "fonts", "DotGothic16.ttf"),
17
+ ]) {
18
+ if (existsSync(candidate))
19
+ return candidate;
20
+ }
21
+ throw new IconRenderError("同梱フォント DotGothic16.ttf が見つかりません。");
22
+ }
23
+ export class IconRenderError extends Error {
24
+ constructor(message) {
25
+ super(message);
26
+ this.name = "IconRenderError";
27
+ }
28
+ }
29
+ /** 絵文字かどうか。異体字セレクタや ZWJ は取り除いてから判定する。 */
30
+ export function isEmoji(glyph) {
31
+ const base = stripEmojiModifiers(glyph);
32
+ return /\p{Extended_Pictographic}/u.test(base);
33
+ }
34
+ /**
35
+ * 絵文字から異体字セレクタ・肌の色・ZWJ 連結を取り除いて、代表となる 1 文字にする。
36
+ * CBDT の索引は単一の符号位置しか引けないため、合字は先頭の絵文字で代表させる。
37
+ */
38
+ export function stripEmojiModifiers(glyph) {
39
+ const cleaned = glyph
40
+ .replace(/[\uFE0E\uFE0F\u200D]/gu, "")
41
+ .replace(/[\u{1F3FB}-\u{1F3FF}]/gu, "");
42
+ return [...cleaned][0] ?? "";
43
+ }
44
+ /**
45
+ * アプリ名から背景色を決める。
46
+ * 同じ名前なら常に同じ色になるので、作り直しても見た目が変わらない。
47
+ */
48
+ const PALETTE = [
49
+ "#2563eb",
50
+ "#059669",
51
+ "#dc2626",
52
+ "#7c3aed",
53
+ "#ea580c",
54
+ "#0891b2",
55
+ "#c026d3",
56
+ "#65a30d",
57
+ ];
58
+ export function backgroundFor(name) {
59
+ let hash = 0;
60
+ for (const char of name) {
61
+ hash = (hash * 31 + char.codePointAt(0)) >>> 0;
62
+ }
63
+ return PALETTE[hash % PALETTE.length];
64
+ }
65
+ /** アプリ名の先頭 1〜2 文字を頭文字として使う。 */
66
+ export function initialsFor(name) {
67
+ const chars = [...name.trim()].filter((char) => !/\s/u.test(char));
68
+ if (chars.length === 0)
69
+ return "?";
70
+ // 日本語は 1 文字で十分に識別できるが、英字は 2 文字あるほうが読みやすい。
71
+ const isLatin = /^[A-Za-z0-9]$/.test(chars[0]);
72
+ return isLatin ? chars.slice(0, 2).join("").toUpperCase() : chars[0];
73
+ }
74
+ function escapeXml(text) {
75
+ return text
76
+ .replace(/&/g, "&amp;")
77
+ .replace(/</g, "&lt;")
78
+ .replace(/>/g, "&gt;")
79
+ .replace(/"/g, "&quot;");
80
+ }
81
+ /** アイコン画像 (PNG) を生成する。 */
82
+ export function renderIcon(options) {
83
+ const { glyph, background } = options;
84
+ const foreground = options.foreground ?? "#ffffff";
85
+ const fontPath = options.fontPath ?? bundledFontPath();
86
+ const radius = Math.round(ICON_SIZE * 0.1875);
87
+ const emojiPng = options.emojiFontPath === null ? null : tryEmojiPng(glyph, options.emojiFontPath);
88
+ const body = emojiPng === null
89
+ ? textBody(glyph, foreground)
90
+ : // 絵文字はフォントから取り出した PNG をそのまま合成する。
91
+ `<image x="${ICON_SIZE * 0.1875}" y="${ICON_SIZE * 0.1875}" ` +
92
+ `width="${ICON_SIZE * 0.625}" height="${ICON_SIZE * 0.625}" ` +
93
+ `preserveAspectRatio="xMidYMid meet" ` +
94
+ `href="data:image/png;base64,${emojiPng.toString("base64")}"/>`;
95
+ const svg = `<svg xmlns="http://www.w3.org/2000/svg" width="${ICON_SIZE}" height="${ICON_SIZE}">` +
96
+ `<rect width="${ICON_SIZE}" height="${ICON_SIZE}" rx="${radius}" fill="${background}"/>` +
97
+ `${body}</svg>`;
98
+ const png = new Resvg(svg, {
99
+ // 同梱フォントだけを使う。実行環境によって見た目が変わらないようにするため。
100
+ font: { fontFiles: [fontPath], loadSystemFonts: false, defaultFontFamily: "DotGothic16" },
101
+ fitTo: { mode: "width", value: ICON_SIZE },
102
+ })
103
+ .render()
104
+ .asPng();
105
+ if (png.length > MAX_ICON_BYTES) {
106
+ throw new IconRenderError(`生成したアイコンが ${Math.round(png.length / 1024)}KB になり、kintone の上限 800KB を超えました。`);
107
+ }
108
+ return { png: Buffer.from(png), mode: emojiPng === null ? "text" : "emoji" };
109
+ }
110
+ function textBody(glyph, foreground) {
111
+ const characters = [...glyph].length;
112
+ // 文字数に応じて、はみ出さない大きさに落とす。
113
+ const fontSize = characters >= 3 ? 72 : characters === 2 ? 104 : 148;
114
+ return (`<text x="${ICON_SIZE / 2}" y="${ICON_SIZE / 2}" font-size="${fontSize}" ` +
115
+ `text-anchor="middle" dominant-baseline="central" fill="${foreground}" ` +
116
+ `font-family="DotGothic16">${escapeXml(glyph)}</text>`);
117
+ }
118
+ function tryEmojiPng(glyph, fontPath) {
119
+ if (!isEmoji(glyph))
120
+ return null;
121
+ const path = fontPath ?? findEmojiFont();
122
+ if (path === null)
123
+ return null;
124
+ const base = stripEmojiModifiers(glyph);
125
+ const codePoint = base.codePointAt(0);
126
+ if (codePoint === undefined)
127
+ return null;
128
+ try {
129
+ return extractEmojiPng(path, codePoint);
130
+ }
131
+ catch {
132
+ // 絵文字を描けないことはアイコンを諦める理由にならない。文字として描く。
133
+ return null;
134
+ }
135
+ }
136
+ //# sourceMappingURL=render.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"render.js","sourceRoot":"","sources":["../../src/icon/render.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,157 @@
1
+ import { KintoneRestAPIClient, KintoneRestAPIError } from "@kintone/rest-api-client";
2
+ import { requireOAuth } from "../config.js";
3
+ import { missingScopes, ReauthRequiredError, refreshAccessToken } from "./oauth.js";
4
+ import { isExpired, loadToken, saveToken } from "./tokenStore.js";
5
+ /** kintone が返すエラー応答。 */
6
+ export class KintoneRequestError extends Error {
7
+ status;
8
+ code;
9
+ constructor(message, status, code) {
10
+ super(message);
11
+ this.status = status;
12
+ this.code = code;
13
+ this.name = "KintoneRequestError";
14
+ }
15
+ }
16
+ /**
17
+ * kintone への 1 リクエストの上限時間。
18
+ * 既定では無制限で、応答が返らないと CLI が黙って止まったままになる。
19
+ */
20
+ export const DEFAULT_SOCKET_TIMEOUT_MS = 60_000;
21
+ /**
22
+ * 保存済みの OAuth トークンで kintone クライアントを組み立てる。
23
+ * アクセストークンは 1 時間で失効する一方リフレッシュトークンは無期限なので、
24
+ * 事前チェックと 401 リトライの二段構えで再ログインをほぼ不要にする。
25
+ */
26
+ export function createAuthenticatedKintone(options) {
27
+ return options.config.auth.kind === "password"
28
+ ? createWithPassword(options)
29
+ : createWithOAuth(options);
30
+ }
31
+ /**
32
+ * パスワード認証のクライアント。
33
+ *
34
+ * 資格情報が固定なので、トークンの保存も更新もスコープの検査も要らない。
35
+ * 401 が返ったら、それは認証情報そのものが正しくないということ。
36
+ */
37
+ function createWithPassword(options) {
38
+ const { config } = options;
39
+ const auth = config.auth;
40
+ const fetchImpl = options.fetchImpl ?? fetch;
41
+ const client = options.clientFactory?.("") ??
42
+ new KintoneRestAPIClient({
43
+ baseUrl: config.baseUrl,
44
+ auth: { username: auth.username, password: auth.password },
45
+ ...(options.guestSpaceId === undefined ? {} : { guestSpaceId: options.guestSpaceId }),
46
+ socketTimeout: options.socketTimeoutMs ?? DEFAULT_SOCKET_TIMEOUT_MS,
47
+ userAgent: USER_AGENT,
48
+ });
49
+ const credentials = Buffer.from(`${auth.username}:${auth.password}`).toString("base64");
50
+ return {
51
+ async call(operation) {
52
+ try {
53
+ return await operation(client);
54
+ }
55
+ catch (error) {
56
+ if (isUnauthorized(error)) {
57
+ throw new ReauthRequiredError(`${config.baseUrl} の認証に失敗しました。` +
58
+ " KINTONE_USERNAME と KINTONE_PASSWORD を確認してください。");
59
+ }
60
+ throw error;
61
+ }
62
+ },
63
+ async request(method, path, body) {
64
+ return await rawRequest({ "X-Cybozu-Authorization": credentials }, config.baseUrl, method, path, body, options.socketTimeoutMs ?? DEFAULT_SOCKET_TIMEOUT_MS, fetchImpl);
65
+ },
66
+ };
67
+ }
68
+ /**
69
+ * OAuth のクライアント。
70
+ *
71
+ * アクセストークンは 1 時間で失効する一方リフレッシュトークンは無期限なので、
72
+ * 事前チェックと 401 リトライの二段構えで再ログインをほぼ不要にする。
73
+ */
74
+ function createWithOAuth(options) {
75
+ const { config, env = process.env, fetchImpl = fetch } = options;
76
+ const oauth = requireOAuth(config);
77
+ const stored = loadToken(config.baseUrl, env);
78
+ if (stored === null) {
79
+ throw new ReauthRequiredError(`${config.baseUrl} の認証情報が見つかりません。\`fieldsmith login\` を実行してください。`);
80
+ }
81
+ // スコープ不足は途中まで成功してから 403 で落ちるという最悪の形で表面化する
82
+ // (アプリだけ作られて残る)。1 リクエストも投げる前に気付けるようにする。
83
+ const missing = missingScopes(stored.scope);
84
+ if (missing.length > 0) {
85
+ throw new ReauthRequiredError(`保存済みの認証情報にスコープ ${missing.join(", ")} が含まれていません。\n` +
86
+ "`fieldsmith login` を実行して認可をやり直してください。");
87
+ }
88
+ let token = stored;
89
+ const factory = options.clientFactory ??
90
+ ((accessToken) => new KintoneRestAPIClient({
91
+ baseUrl: config.baseUrl,
92
+ auth: { oAuthToken: accessToken },
93
+ ...(options.guestSpaceId === undefined ? {} : { guestSpaceId: options.guestSpaceId }),
94
+ socketTimeout: options.socketTimeoutMs ?? DEFAULT_SOCKET_TIMEOUT_MS,
95
+ userAgent: USER_AGENT,
96
+ }));
97
+ const refresh = async () => {
98
+ token = await refreshAccessToken(oauth, token.refreshToken, fetchImpl);
99
+ saveToken(config.baseUrl, token, env);
100
+ };
101
+ return {
102
+ async call(operation) {
103
+ if (isExpired(token)) {
104
+ await refresh();
105
+ }
106
+ try {
107
+ return await operation(factory(token.accessToken));
108
+ }
109
+ catch (error) {
110
+ if (!isUnauthorized(error))
111
+ throw error;
112
+ // 期限内でも失効しているケース (トークン失効・スコープ変更など) がある。
113
+ await refresh();
114
+ return await operation(factory(token.accessToken));
115
+ }
116
+ },
117
+ async request(method, path, body) {
118
+ if (isExpired(token)) {
119
+ await refresh();
120
+ }
121
+ const send = () => rawRequest({ Authorization: `Bearer ${token.accessToken}` }, config.baseUrl, method, path, body, options.socketTimeoutMs ?? DEFAULT_SOCKET_TIMEOUT_MS, fetchImpl);
122
+ try {
123
+ return await send();
124
+ }
125
+ catch (error) {
126
+ if (!(error instanceof KintoneRequestError) || error.status !== 401)
127
+ throw error;
128
+ await refresh();
129
+ return await send();
130
+ }
131
+ },
132
+ };
133
+ }
134
+ const USER_AGENT = "fieldsmith";
135
+ /** 認証ヘッダーだけを差し替えて REST API を直接叩く。 */
136
+ async function rawRequest(authHeaders, baseUrl, method, path, body, timeoutMs, fetchImpl) {
137
+ const response = await fetchImpl(`${baseUrl}${path}`, {
138
+ method,
139
+ headers: { ...authHeaders, "Content-Type": "application/json" },
140
+ ...(body === undefined ? {} : { body: JSON.stringify(body) }),
141
+ signal: AbortSignal.timeout(timeoutMs),
142
+ });
143
+ const text = await response.text();
144
+ const parsed = text === "" ? {} : JSON.parse(text);
145
+ if (!response.ok) {
146
+ throw new KintoneRequestError(typeof parsed["message"] === "string" ? parsed["message"] : `HTTP ${response.status}`, response.status, typeof parsed["code"] === "string" ? parsed["code"] : undefined);
147
+ }
148
+ return parsed;
149
+ }
150
+ /** ゲストスペースかどうかで API のパスの前置きが変わる。 */
151
+ export function apiPathPrefix(guestSpaceId) {
152
+ return guestSpaceId === undefined ? "/k/v1" : `/k/guest/${guestSpaceId}/v1`;
153
+ }
154
+ function isUnauthorized(error) {
155
+ return error instanceof KintoneRestAPIError && error.status === 401;
156
+ }
157
+ //# sourceMappingURL=client.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"client.js","sourceRoot":"","sources":["../../src/kintone/client.ts"],"names":[],"mappings":"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"}