@volter/twin-googlefonts 0.0.0-stage → 1.0.1
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 +202 -0
- package/README.md +15 -2
- package/api/spec/SOURCE.md +17 -0
- package/api/spec/discovery.json +306 -0
- package/api/spec/openapi.json +647 -0
- package/api/spec/sources.json +6 -0
- package/api/src/fetch.ts +16 -0
- package/api/src/generated/surface.gen.json +1 -0
- package/api/src/generated/ui.gen.json +1 -0
- package/api/src/index.ts +3 -0
- package/api/src/manifest.ts +31 -0
- package/api/src/semantics/doors.ts +131 -0
- package/api/src/semantics/index.ts +8 -0
- package/api/src/semantics/shared.ts +1 -0
- package/api/src/semantics/states.ts +6 -0
- package/api/src/semantics/webfonts.ts +32 -0
- package/assets/spec/SOURCE.md +11 -0
- package/assets/spec/openapi.json +162 -0
- package/assets/spec/sources.json +1 -0
- package/assets/src/fetch.ts +14 -0
- package/assets/src/generated/surface.gen.json +1 -0
- package/assets/src/generated/ui.gen.json +1 -0
- package/assets/src/index.ts +3 -0
- package/assets/src/manifest.ts +19 -0
- package/assets/src/semantics/index.ts +10 -0
- package/assets/src/semantics/l.ts +4 -0
- package/assets/src/semantics/s.ts +4 -0
- package/assets/src/semantics/shared.ts +13 -0
- package/css/spec/SOURCE.md +15 -0
- package/css/spec/openapi.json +142 -0
- package/css/spec/sources.json +1 -0
- package/css/src/fetch.ts +14 -0
- package/css/src/generated/surface.gen.json +1 -0
- package/css/src/generated/ui.gen.json +1 -0
- package/css/src/index.ts +3 -0
- package/css/src/manifest.ts +19 -0
- package/css/src/semantics/css.ts +19 -0
- package/css/src/semantics/css2.ts +20 -0
- package/css/src/semantics/index.ts +10 -0
- package/css/src/semantics/shared.ts +1 -0
- package/dist/api/spec/SOURCE.md +17 -0
- package/dist/api/spec/discovery.json +306 -0
- package/dist/api/spec/openapi.json +647 -0
- package/dist/api/spec/sources.json +6 -0
- package/dist/api/src/fetch.d.ts +2 -0
- package/dist/api/src/fetch.js +15 -0
- package/dist/api/src/fetch.ts +16 -0
- package/dist/api/src/generated/surface.gen.json +1 -0
- package/dist/api/src/generated/ui.gen.json +1 -0
- package/dist/api/src/index.d.ts +2 -0
- package/dist/api/src/index.js +3 -0
- package/dist/api/src/index.ts +3 -0
- package/dist/api/src/manifest.d.ts +2 -0
- package/dist/api/src/manifest.js +29 -0
- package/dist/api/src/manifest.ts +31 -0
- package/dist/api/src/semantics/doors.d.ts +3 -0
- package/dist/api/src/semantics/doors.js +138 -0
- package/dist/api/src/semantics/doors.ts +131 -0
- package/dist/api/src/semantics/index.d.ts +2 -0
- package/dist/api/src/semantics/index.js +4 -0
- package/dist/api/src/semantics/index.ts +8 -0
- package/dist/api/src/semantics/shared.d.ts +1 -0
- package/dist/api/src/semantics/shared.js +1 -0
- package/dist/api/src/semantics/shared.ts +1 -0
- package/dist/api/src/semantics/states.d.ts +8 -0
- package/dist/api/src/semantics/states.js +6 -0
- package/dist/api/src/semantics/states.ts +6 -0
- package/dist/api/src/semantics/webfonts.d.ts +2 -0
- package/dist/api/src/semantics/webfonts.js +34 -0
- package/dist/api/src/semantics/webfonts.ts +32 -0
- package/dist/assets/spec/SOURCE.md +11 -0
- package/dist/assets/spec/openapi.json +162 -0
- package/dist/assets/spec/sources.json +1 -0
- package/dist/assets/src/fetch.d.ts +2 -0
- package/dist/assets/src/fetch.js +13 -0
- package/dist/assets/src/fetch.ts +14 -0
- package/dist/assets/src/generated/surface.gen.json +1 -0
- package/dist/assets/src/generated/ui.gen.json +1 -0
- package/dist/assets/src/index.d.ts +2 -0
- package/dist/assets/src/index.js +3 -0
- package/dist/assets/src/index.ts +3 -0
- package/dist/assets/src/manifest.d.ts +2 -0
- package/dist/assets/src/manifest.js +17 -0
- package/dist/assets/src/manifest.ts +19 -0
- package/dist/assets/src/semantics/index.d.ts +2 -0
- package/dist/assets/src/semantics/index.js +6 -0
- package/dist/assets/src/semantics/index.ts +10 -0
- package/dist/assets/src/semantics/l.d.ts +2 -0
- package/dist/assets/src/semantics/l.js +3 -0
- package/dist/assets/src/semantics/l.ts +4 -0
- package/dist/assets/src/semantics/s.d.ts +2 -0
- package/dist/assets/src/semantics/s.js +3 -0
- package/dist/assets/src/semantics/s.ts +4 -0
- package/dist/assets/src/semantics/shared.d.ts +2 -0
- package/dist/assets/src/semantics/shared.js +13 -0
- package/dist/assets/src/semantics/shared.ts +13 -0
- package/dist/css/spec/SOURCE.md +15 -0
- package/dist/css/spec/openapi.json +142 -0
- package/dist/css/spec/sources.json +1 -0
- package/dist/css/src/fetch.d.ts +2 -0
- package/dist/css/src/fetch.js +13 -0
- package/dist/css/src/fetch.ts +14 -0
- package/dist/css/src/generated/surface.gen.json +1 -0
- package/dist/css/src/generated/ui.gen.json +1 -0
- package/dist/css/src/index.d.ts +2 -0
- package/dist/css/src/index.js +3 -0
- package/dist/css/src/index.ts +3 -0
- package/dist/css/src/manifest.d.ts +2 -0
- package/dist/css/src/manifest.js +16 -0
- package/dist/css/src/manifest.ts +19 -0
- package/dist/css/src/semantics/css.d.ts +2 -0
- package/dist/css/src/semantics/css.js +19 -0
- package/dist/css/src/semantics/css.ts +19 -0
- package/dist/css/src/semantics/css2.d.ts +2 -0
- package/dist/css/src/semantics/css2.js +21 -0
- package/dist/css/src/semantics/css2.ts +20 -0
- package/dist/css/src/semantics/index.d.ts +2 -0
- package/dist/css/src/semantics/index.js +6 -0
- package/dist/css/src/semantics/index.ts +10 -0
- package/dist/css/src/semantics/shared.d.ts +1 -0
- package/dist/css/src/semantics/shared.js +1 -0
- package/dist/css/src/semantics/shared.ts +1 -0
- package/dist/journeys/customer-life.json +463 -0
- package/dist/journeys/customer-life.outline.md +24 -0
- package/dist/journeys/customer-life.outline.verdict.json +82 -0
- package/dist/journeys/customer-life.verdict.json +149 -0
- package/dist/journeys/decisions.json +54 -0
- package/dist/journeys/demand.json +67 -0
- package/dist/journeys/first-use.json +20 -0
- package/dist/src/cli.d.ts +2 -0
- package/dist/src/cli.js +21 -0
- package/dist/src/fetch.d.ts +2 -0
- package/dist/src/fetch.js +10 -0
- package/dist/src/index.d.ts +5 -0
- package/dist/src/index.js +15 -0
- package/dist/src/manifest.d.ts +2 -0
- package/dist/src/manifest.js +25 -0
- package/dist/src/semantics/seed.d.ts +2 -0
- package/dist/src/semantics/seed.js +141 -0
- package/dist/src/semantics/shared.d.ts +9 -0
- package/dist/src/semantics/shared.js +23 -0
- package/dist/src/server.d.ts +7 -0
- package/dist/src/server.js +7 -0
- package/dist/vendor/Inter-OFL.txt +93 -0
- package/dist/vendor/OFL.txt +94 -0
- package/dist/vendor/SOURCE.md +33 -0
- package/dist/vendor/antic.json +93 -0
- package/dist/vendor/inputs.json +460 -0
- package/dist/vendor/inter.json +44 -0
- package/dist/vendor/noto-sans-sc-text.json +24 -0
- package/generated/pack-facts.json +65 -0
- package/journeys/customer-life.json +463 -0
- package/journeys/customer-life.outline.md +24 -0
- package/journeys/customer-life.outline.verdict.json +82 -0
- package/journeys/customer-life.verdict.json +149 -0
- package/journeys/decisions.json +54 -0
- package/journeys/demand.json +67 -0
- package/journeys/first-use.json +20 -0
- package/package.json +41 -4
- package/src/cli.ts +22 -0
- package/src/fetch.ts +11 -0
- package/src/index.ts +17 -0
- package/src/manifest.ts +27 -0
- package/src/semantics/seed.ts +143 -0
- package/src/semantics/shared.ts +25 -0
- package/src/server.ts +8 -0
- package/vendor/Inter-OFL.txt +93 -0
- package/vendor/OFL.txt +94 -0
- package/vendor/SOURCE.md +33 -0
- package/vendor/antic.json +93 -0
- package/vendor/inputs.json +460 -0
- package/vendor/inter.json +44 -0
- package/vendor/noto-sans-sc-text.json +24 -0
|
@@ -0,0 +1,162 @@
|
|
|
1
|
+
{
|
|
2
|
+
"openapi": "3.0.3",
|
|
3
|
+
"info": {
|
|
4
|
+
"title": "Google Fonts font-file hosts",
|
|
5
|
+
"version": "2026-10-12"
|
|
6
|
+
},
|
|
7
|
+
"servers": [
|
|
8
|
+
{
|
|
9
|
+
"url": "https://fonts.gstatic.com"
|
|
10
|
+
}
|
|
11
|
+
],
|
|
12
|
+
"paths": {
|
|
13
|
+
"/s/{file}": {
|
|
14
|
+
"get": {
|
|
15
|
+
"operationId": "getFontFile",
|
|
16
|
+
"description": "Download the font-file bytes named by a Google Fonts stylesheet src URL.",
|
|
17
|
+
"parameters": [
|
|
18
|
+
{
|
|
19
|
+
"name": "file",
|
|
20
|
+
"in": "path",
|
|
21
|
+
"required": true,
|
|
22
|
+
"schema": {
|
|
23
|
+
"type": "string"
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
],
|
|
27
|
+
"responses": {
|
|
28
|
+
"200": {
|
|
29
|
+
"description": "The font-file bytes at the returned stylesheet URL",
|
|
30
|
+
"content": {
|
|
31
|
+
"font/eot": {
|
|
32
|
+
"schema": {
|
|
33
|
+
"type": "string",
|
|
34
|
+
"format": "binary"
|
|
35
|
+
}
|
|
36
|
+
},
|
|
37
|
+
"font/ttf": {
|
|
38
|
+
"schema": {
|
|
39
|
+
"type": "string",
|
|
40
|
+
"format": "binary"
|
|
41
|
+
}
|
|
42
|
+
},
|
|
43
|
+
"font/woff": {
|
|
44
|
+
"schema": {
|
|
45
|
+
"type": "string",
|
|
46
|
+
"format": "binary"
|
|
47
|
+
}
|
|
48
|
+
},
|
|
49
|
+
"font/woff2": {
|
|
50
|
+
"schema": {
|
|
51
|
+
"type": "string",
|
|
52
|
+
"format": "binary"
|
|
53
|
+
}
|
|
54
|
+
},
|
|
55
|
+
"image/svg+xml": {
|
|
56
|
+
"schema": {
|
|
57
|
+
"type": "string",
|
|
58
|
+
"format": "binary"
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
},
|
|
63
|
+
"404": {
|
|
64
|
+
"description": "Font file not found",
|
|
65
|
+
"content": {
|
|
66
|
+
"text/html": {
|
|
67
|
+
"schema": {
|
|
68
|
+
"type": "string"
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
},
|
|
74
|
+
"tags": [
|
|
75
|
+
"files"
|
|
76
|
+
]
|
|
77
|
+
}
|
|
78
|
+
},
|
|
79
|
+
"/l/font": {
|
|
80
|
+
"get": {
|
|
81
|
+
"operationId": "getLegacyFontFile",
|
|
82
|
+
"description": "Download the font-file bytes named by a Google Fonts stylesheet src URL for a legacy browser.",
|
|
83
|
+
"parameters": [
|
|
84
|
+
{
|
|
85
|
+
"name": "kit",
|
|
86
|
+
"in": "query",
|
|
87
|
+
"required": true,
|
|
88
|
+
"schema": {
|
|
89
|
+
"type": "string"
|
|
90
|
+
}
|
|
91
|
+
},
|
|
92
|
+
{
|
|
93
|
+
"name": "skey",
|
|
94
|
+
"in": "query",
|
|
95
|
+
"required": true,
|
|
96
|
+
"schema": {
|
|
97
|
+
"type": "string"
|
|
98
|
+
}
|
|
99
|
+
},
|
|
100
|
+
{
|
|
101
|
+
"name": "v",
|
|
102
|
+
"in": "query",
|
|
103
|
+
"required": true,
|
|
104
|
+
"schema": {
|
|
105
|
+
"type": "string"
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
],
|
|
109
|
+
"responses": {
|
|
110
|
+
"200": {
|
|
111
|
+
"description": "The font-file bytes at the returned stylesheet URL",
|
|
112
|
+
"content": {
|
|
113
|
+
"font/eot": {
|
|
114
|
+
"schema": {
|
|
115
|
+
"type": "string",
|
|
116
|
+
"format": "binary"
|
|
117
|
+
}
|
|
118
|
+
},
|
|
119
|
+
"font/ttf": {
|
|
120
|
+
"schema": {
|
|
121
|
+
"type": "string",
|
|
122
|
+
"format": "binary"
|
|
123
|
+
}
|
|
124
|
+
},
|
|
125
|
+
"font/woff": {
|
|
126
|
+
"schema": {
|
|
127
|
+
"type": "string",
|
|
128
|
+
"format": "binary"
|
|
129
|
+
}
|
|
130
|
+
},
|
|
131
|
+
"font/woff2": {
|
|
132
|
+
"schema": {
|
|
133
|
+
"type": "string",
|
|
134
|
+
"format": "binary"
|
|
135
|
+
}
|
|
136
|
+
},
|
|
137
|
+
"image/svg+xml": {
|
|
138
|
+
"schema": {
|
|
139
|
+
"type": "string",
|
|
140
|
+
"format": "binary"
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
},
|
|
145
|
+
"404": {
|
|
146
|
+
"description": "Font file not found",
|
|
147
|
+
"content": {
|
|
148
|
+
"text/html": {
|
|
149
|
+
"schema": {
|
|
150
|
+
"type": "string"
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
},
|
|
156
|
+
"tags": [
|
|
157
|
+
"files"
|
|
158
|
+
]
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
// GENERATED by scripts/create-pack.ts (--init, --index): a fixed file. The kernel serves the discovery door, the clock,
|
|
2
|
+
// the World's doors, the vendor's screens and the API from the pack's parts (architecture, "The pack contract").
|
|
3
|
+
import { createPackFetch } from '@volter/world-core';
|
|
4
|
+
import surface from './generated/surface.gen.json' with { type: 'json' };
|
|
5
|
+
import { manifest } from "./manifest.js";
|
|
6
|
+
import { assetsSemantics } from "./semantics/index.js";
|
|
7
|
+
export function createAssetsLaneFetch(options = {}) {
|
|
8
|
+
return createPackFetch({
|
|
9
|
+
manifest,
|
|
10
|
+
surface: surface,
|
|
11
|
+
handlers: assetsSemantics,
|
|
12
|
+
}, options);
|
|
13
|
+
}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
// GENERATED by scripts/create-pack.ts (--init, --index): a fixed file. The kernel serves the discovery door, the clock,
|
|
2
|
+
// the World's doors, the vendor's screens and the API from the pack's parts (architecture, "The pack contract").
|
|
3
|
+
import { createPackFetch, type DerivedFetch, type DerivedSurface, type PackFetchOptions } from '@volter/world-core';
|
|
4
|
+
import surface from './generated/surface.gen.json' with { type: 'json' };
|
|
5
|
+
import { manifest } from './manifest.ts';
|
|
6
|
+
import { assetsSemantics } from './semantics/index.ts';
|
|
7
|
+
|
|
8
|
+
export function createAssetsLaneFetch(options: PackFetchOptions = {}): DerivedFetch {
|
|
9
|
+
return createPackFetch({
|
|
10
|
+
manifest,
|
|
11
|
+
surface: surface as DerivedSurface,
|
|
12
|
+
handlers: assetsSemantics,
|
|
13
|
+
}, options);
|
|
14
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"generatedBy":"scripts/derive-pack.ts","spec":"openapi.json","format":"openapi","version":"2026-10-12","resources":[],"operations":[{"id":"getLegacyFontFile","method":"get","path":"/l/font","pathParams":[],"query":[{"name":"kit","type":"string","required":true},{"name":"skey","type":"string","required":true},{"name":"v","type":"string","required":true}],"body":[],"bodyEncoding":"none","successStatus":200,"responseMedia":{"200":["image/svg+xml"]},"class":"computed"},{"id":"getFontFile","method":"get","path":"/s/{file}","pathParams":["file"],"query":[],"body":[],"bodyEncoding":"none","successStatus":200,"responseMedia":{"200":["image/svg+xml"]},"class":"computed"}]}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"generatedBy":"scripts/derive-pack.ts","resources":{}}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
export const manifest = {
|
|
2
|
+
vendor: 'googlefonts', service: 'googlefonts', body: { json: 'always' },
|
|
3
|
+
ids: { template: '{uuid}' }, time: 'iso',
|
|
4
|
+
error: { error: { code: '{status}', message: '{message}', status: '{kind}' } },
|
|
5
|
+
readOnly: { status: 403, kind: 'PERMISSION_DENIED', message: 'Read-only World' },
|
|
6
|
+
notFound: { status: 404, kind: 'NOT_FOUND', message: 'Not Found' },
|
|
7
|
+
gap: { status: 404, kind: 'NOT_FOUND', message: 'Not Found' },
|
|
8
|
+
list: { style: 'envelope', envelope: { items: '{data}' }, limit: { param: 'limit', default: 100, max: 100 } },
|
|
9
|
+
deleted: {},
|
|
10
|
+
resources: {},
|
|
11
|
+
discovery: { twinOf: 'Google Fonts font bytes', stores: 'Published catalog and font representations in the shared googlefonts store' },
|
|
12
|
+
spanning: ['file'],
|
|
13
|
+
descriptor: { protocol: '3', transport: 'rest', archetype: 'crud', bin: 'world-googlefonts-assets',
|
|
14
|
+
resources: [], specSource: 'assets/spec/SOURCE.md', description: 'Google Fonts font bytes',
|
|
15
|
+
adoption: { sdks: [], envStems: [] }, hosts: [{ host: 'fonts.gstatic.com', pathPattern: '^/(s/|l/font$)' }],
|
|
16
|
+
endpointEnvNone: 'The application hardcodes this vendor lane host.' },
|
|
17
|
+
};
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
// Vendor wire facts; the surface is derived from the retained spec.
|
|
2
|
+
import type { DerivedManifest } from '@volter/world-core';
|
|
3
|
+
export const manifest: DerivedManifest = {
|
|
4
|
+
vendor: 'googlefonts', service: 'googlefonts', body: { json: 'always' },
|
|
5
|
+
ids: { template: '{uuid}' }, time: 'iso',
|
|
6
|
+
error: { error: { code: '{status}', message: '{message}', status: '{kind}' } },
|
|
7
|
+
readOnly: { status: 403, kind: 'PERMISSION_DENIED', message: 'Read-only World' },
|
|
8
|
+
notFound: { status: 404, kind: 'NOT_FOUND', message: 'Not Found' },
|
|
9
|
+
gap: { status: 404, kind: 'NOT_FOUND', message: 'Not Found' },
|
|
10
|
+
list: { style: 'envelope', envelope: { items: '{data}' }, limit: { param: 'limit', default: 100, max: 100 } },
|
|
11
|
+
deleted: {},
|
|
12
|
+
resources: {},
|
|
13
|
+
discovery: { twinOf: 'Google Fonts font bytes', stores: 'Published catalog and font representations in the shared googlefonts store' },
|
|
14
|
+
spanning: ['file'],
|
|
15
|
+
descriptor: { protocol: '3', transport: 'rest', archetype: 'crud', bin: 'world-googlefonts-assets',
|
|
16
|
+
resources: [], specSource: 'assets/spec/SOURCE.md', description: 'Google Fonts font bytes',
|
|
17
|
+
adoption: { sdks: [], envStems: [] }, hosts: [{ host: 'fonts.gstatic.com', pathPattern: '^/(s/|l/font$)' }],
|
|
18
|
+
endpointEnvNone: 'The application hardcodes this vendor lane host.' },
|
|
19
|
+
};
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
// GENERATED by scripts/create-pack.ts --index: the handler map, by operationId, from the families' files (each
|
|
2
|
+
// handler named as its operation). Do not edit; add a handler to its family's file and generate again.
|
|
3
|
+
import type { Handler } from '@volter/world-core';
|
|
4
|
+
import * as l from './l.ts';
|
|
5
|
+
import * as s from './s.ts';
|
|
6
|
+
|
|
7
|
+
export const assetsSemantics: Record<string, Handler> = {
|
|
8
|
+
getFontFile: s.getFontFile,
|
|
9
|
+
getLegacyFontFile: l.getLegacyFontFile,
|
|
10
|
+
};
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
import type { HandlerContext } from '@volter/world-core';
|
|
2
|
+
import { downloadFont } from './shared.ts';
|
|
3
|
+
// source: spec:getLegacyFontFile "Download the font-file bytes named by a Google Fonts stylesheet src URL for a legacy browser."
|
|
4
|
+
export async function getLegacyFontFile(ctx: HandlerContext): Promise<Response> { return downloadFont(ctx); }
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
import type { HandlerContext } from '@volter/world-core';
|
|
2
|
+
import { downloadFont } from './shared.ts';
|
|
3
|
+
// source: spec:getFontFile "Download the font-file bytes named by a Google Fonts stylesheet src URL."
|
|
4
|
+
export async function getFontFile(ctx: HandlerContext): Promise<Response> { return downloadFont(ctx); }
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { FILE, assetKey, htmlError } from "../../../src/semantics/shared.js";
|
|
2
|
+
export async function downloadFont(ctx) {
|
|
3
|
+
const request = new URL(ctx.call.request.url);
|
|
4
|
+
const vendorUrl = new URL(request.pathname + request.search, 'https://fonts.gstatic.com');
|
|
5
|
+
const row = ctx.row(FILE, assetKey(vendorUrl.href));
|
|
6
|
+
if (!row)
|
|
7
|
+
return htmlError(404, 'Font file not found');
|
|
8
|
+
const body = await ctx.blobs.get(String(row.blob));
|
|
9
|
+
if (!body)
|
|
10
|
+
return htmlError(404, 'Font file not found');
|
|
11
|
+
return new Response(Uint8Array.from(body).buffer, { headers: { 'content-type': String(row.contentType), 'content-length': String(body.length),
|
|
12
|
+
'access-control-allow-origin': '*', 'cache-control': 'public, max-age=31536000, immutable' } });
|
|
13
|
+
}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import type { HandlerContext } from '@volter/world-core';
|
|
2
|
+
import { FILE, assetKey, htmlError } from '../../../src/semantics/shared.ts';
|
|
3
|
+
|
|
4
|
+
export async function downloadFont(ctx: HandlerContext): Promise<Response> {
|
|
5
|
+
const request = new URL(ctx.call.request.url);
|
|
6
|
+
const vendorUrl = new URL(request.pathname + request.search, 'https://fonts.gstatic.com');
|
|
7
|
+
const row = ctx.row(FILE, assetKey(vendorUrl.href));
|
|
8
|
+
if (!row) return htmlError(404, 'Font file not found');
|
|
9
|
+
const body = await ctx.blobs.get(String(row.blob));
|
|
10
|
+
if (!body) return htmlError(404, 'Font file not found');
|
|
11
|
+
return new Response(Uint8Array.from(body).buffer, { headers: { 'content-type': String(row.contentType), 'content-length': String(body.length),
|
|
12
|
+
'access-control-allow-origin': '*', 'cache-control': 'public, max-age=31536000, immutable' } });
|
|
13
|
+
}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
# Google Fonts CSS API v1 and CSS2
|
|
2
|
+
|
|
3
|
+
This contract is written from Google's https://developers.google.com/fonts/docs/getting_started,
|
|
4
|
+
https://developers.google.com/fonts/docs/css2 and the retained responses in vendor/inputs.json,
|
|
5
|
+
vendor/inter.json and vendor/noto-sans-sc-text.json. google-webfonts-helper calls
|
|
6
|
+
GET /css?family=<family>:<variant>&subset=<subsets> with the exact configured
|
|
7
|
+
User-Agent and consumes each @font-face's font-family, style, weight and src URL.
|
|
8
|
+
Dub's Open Graph routes call GET /css2?family=Inter:wght@<weight> and Rallly's
|
|
9
|
+
calls GET /css2?family=Noto+Sans+SC:wght@<weight>&text=<text>, both from a server
|
|
10
|
+
without a browser User-Agent, and read the truetype src URL.
|
|
11
|
+
The supplied representations retain actual vendor CSS. Requests without a
|
|
12
|
+
published representation answer a refusal, never an invented font format.
|
|
13
|
+
text/display/effect on /css are outside this client's demand.
|
|
14
|
+
|
|
15
|
+
SHA-256 `openapi.json`: bf7b9a3b70c3a75712fb784e22bfe07c0008dd55e1aa93b31cba8da26a64fb60
|
|
@@ -0,0 +1,142 @@
|
|
|
1
|
+
{
|
|
2
|
+
"openapi": "3.0.3",
|
|
3
|
+
"info": {
|
|
4
|
+
"title": "Google Fonts CSS API",
|
|
5
|
+
"version": "v1"
|
|
6
|
+
},
|
|
7
|
+
"servers": [
|
|
8
|
+
{
|
|
9
|
+
"url": "https://fonts.googleapis.com"
|
|
10
|
+
}
|
|
11
|
+
],
|
|
12
|
+
"paths": {
|
|
13
|
+
"/css": {
|
|
14
|
+
"get": {
|
|
15
|
+
"operationId": "getStylesheet",
|
|
16
|
+
"description": "The Google Fonts API provides the regular version of the requested fonts by default. To request other styles or weights, append a colon to the name of the font. The subset parameter specifies script subsets. The representation is selected for the requesting browser.",
|
|
17
|
+
"parameters": [
|
|
18
|
+
{
|
|
19
|
+
"name": "family",
|
|
20
|
+
"in": "query",
|
|
21
|
+
"required": true,
|
|
22
|
+
"schema": {
|
|
23
|
+
"type": "string"
|
|
24
|
+
}
|
|
25
|
+
},
|
|
26
|
+
{
|
|
27
|
+
"name": "subset",
|
|
28
|
+
"in": "query",
|
|
29
|
+
"required": false,
|
|
30
|
+
"schema": {
|
|
31
|
+
"type": "string"
|
|
32
|
+
}
|
|
33
|
+
},
|
|
34
|
+
{
|
|
35
|
+
"name": "User-Agent",
|
|
36
|
+
"in": "header",
|
|
37
|
+
"schema": {
|
|
38
|
+
"type": "string"
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
],
|
|
42
|
+
"responses": {
|
|
43
|
+
"200": {
|
|
44
|
+
"description": "A stylesheet referring to font-file URLs",
|
|
45
|
+
"content": {
|
|
46
|
+
"text/css": {
|
|
47
|
+
"schema": {
|
|
48
|
+
"type": "string"
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
},
|
|
53
|
+
"400": {
|
|
54
|
+
"description": "Bad font request",
|
|
55
|
+
"content": {
|
|
56
|
+
"text/html": {
|
|
57
|
+
"schema": {
|
|
58
|
+
"type": "string"
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
},
|
|
66
|
+
"/css2": {
|
|
67
|
+
"get": {
|
|
68
|
+
"operationId": "getStylesheet2",
|
|
69
|
+
"description": "It all starts with a new base URL: https://fonts.googleapis.com/css2 The syntax for specifying styles within each family has changed to describe variable font ‘design spaces.’ To request multiple families, specify the family= param for each family. Please note that the 'text=' parameter can only be specified once. It applies to all families in the request. As a general note, the updated CSS API is more strict about what requests are accepted than the original CSS API. The representation is selected for the requesting browser.",
|
|
70
|
+
"parameters": [
|
|
71
|
+
{
|
|
72
|
+
"name": "family",
|
|
73
|
+
"in": "query",
|
|
74
|
+
"required": true,
|
|
75
|
+
"style": "form",
|
|
76
|
+
"explode": true,
|
|
77
|
+
"description": "<family_name>[:<axis_tag_list>@<axis_tuple_list>]",
|
|
78
|
+
"schema": {
|
|
79
|
+
"type": "array",
|
|
80
|
+
"items": {
|
|
81
|
+
"type": "string"
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
},
|
|
85
|
+
{
|
|
86
|
+
"name": "text",
|
|
87
|
+
"in": "query",
|
|
88
|
+
"required": false,
|
|
89
|
+
"description": "The text that will be displayed in the requested typeface",
|
|
90
|
+
"schema": {
|
|
91
|
+
"type": "string"
|
|
92
|
+
}
|
|
93
|
+
},
|
|
94
|
+
{
|
|
95
|
+
"name": "display",
|
|
96
|
+
"in": "query",
|
|
97
|
+
"required": false,
|
|
98
|
+
"schema": {
|
|
99
|
+
"type": "string",
|
|
100
|
+
"enum": [
|
|
101
|
+
"auto",
|
|
102
|
+
"block",
|
|
103
|
+
"swap",
|
|
104
|
+
"fallback",
|
|
105
|
+
"optional"
|
|
106
|
+
]
|
|
107
|
+
}
|
|
108
|
+
},
|
|
109
|
+
{
|
|
110
|
+
"name": "User-Agent",
|
|
111
|
+
"in": "header",
|
|
112
|
+
"schema": {
|
|
113
|
+
"type": "string"
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
],
|
|
117
|
+
"responses": {
|
|
118
|
+
"200": {
|
|
119
|
+
"description": "A stylesheet referring to font-file URLs",
|
|
120
|
+
"content": {
|
|
121
|
+
"text/css": {
|
|
122
|
+
"schema": {
|
|
123
|
+
"type": "string"
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
},
|
|
128
|
+
"400": {
|
|
129
|
+
"description": "Bad font request",
|
|
130
|
+
"content": {
|
|
131
|
+
"text/html": {
|
|
132
|
+
"schema": {
|
|
133
|
+
"type": "string"
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
// GENERATED by scripts/create-pack.ts (--init, --index): a fixed file. The kernel serves the discovery door, the clock,
|
|
2
|
+
// the World's doors, the vendor's screens and the API from the pack's parts (architecture, "The pack contract").
|
|
3
|
+
import { createPackFetch } from '@volter/world-core';
|
|
4
|
+
import surface from './generated/surface.gen.json' with { type: 'json' };
|
|
5
|
+
import { manifest } from "./manifest.js";
|
|
6
|
+
import { cssSemantics } from "./semantics/index.js";
|
|
7
|
+
export function createCssLaneFetch(options = {}) {
|
|
8
|
+
return createPackFetch({
|
|
9
|
+
manifest,
|
|
10
|
+
surface: surface,
|
|
11
|
+
handlers: cssSemantics,
|
|
12
|
+
}, options);
|
|
13
|
+
}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
// GENERATED by scripts/create-pack.ts (--init, --index): a fixed file. The kernel serves the discovery door, the clock,
|
|
2
|
+
// the World's doors, the vendor's screens and the API from the pack's parts (architecture, "The pack contract").
|
|
3
|
+
import { createPackFetch, type DerivedFetch, type DerivedSurface, type PackFetchOptions } from '@volter/world-core';
|
|
4
|
+
import surface from './generated/surface.gen.json' with { type: 'json' };
|
|
5
|
+
import { manifest } from './manifest.ts';
|
|
6
|
+
import { cssSemantics } from './semantics/index.ts';
|
|
7
|
+
|
|
8
|
+
export function createCssLaneFetch(options: PackFetchOptions = {}): DerivedFetch {
|
|
9
|
+
return createPackFetch({
|
|
10
|
+
manifest,
|
|
11
|
+
surface: surface as DerivedSurface,
|
|
12
|
+
handlers: cssSemantics,
|
|
13
|
+
}, options);
|
|
14
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"generatedBy":"scripts/derive-pack.ts","spec":"openapi.json","format":"openapi","version":"v1","resources":[],"operations":[{"id":"getStylesheet","method":"get","path":"/css","pathParams":[],"query":[{"name":"family","type":"string","required":true},{"name":"subset","type":"string","required":false}],"body":[],"bodyEncoding":"none","successStatus":200,"class":"computed"},{"id":"getStylesheet2","method":"get","path":"/css2","pathParams":[],"query":[{"name":"display","type":"string","required":false},{"name":"family","type":"array","required":true},{"name":"text","type":"string","required":false}],"body":[],"bodyEncoding":"none","successStatus":200,"class":"computed"}]}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"generatedBy":"scripts/derive-pack.ts","resources":{}}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
export const manifest = {
|
|
2
|
+
vendor: 'googlefonts', service: 'googlefonts', body: { json: 'always' },
|
|
3
|
+
ids: { template: '{uuid}' }, time: 'iso',
|
|
4
|
+
error: { error: { code: '{status}', message: '{message}', status: '{kind}' } },
|
|
5
|
+
readOnly: { status: 403, kind: 'PERMISSION_DENIED', message: 'Read-only World' },
|
|
6
|
+
notFound: { status: 404, kind: 'NOT_FOUND', message: 'Not Found' },
|
|
7
|
+
gap: { status: 404, kind: 'NOT_FOUND', message: 'Not Found' },
|
|
8
|
+
list: { style: 'envelope', envelope: { items: '{data}' }, limit: { param: 'limit', default: 100, max: 100 } },
|
|
9
|
+
deleted: {},
|
|
10
|
+
resources: {},
|
|
11
|
+
discovery: { twinOf: 'Google Fonts browser-selected CSS', stores: 'Published catalog and font representations in the shared googlefonts store' },
|
|
12
|
+
descriptor: { protocol: '3', transport: 'rest', archetype: 'crud', bin: 'world-googlefonts-css',
|
|
13
|
+
resources: [], specSource: 'css/spec/SOURCE.md', description: 'Google Fonts browser-selected CSS',
|
|
14
|
+
adoption: { sdks: [], envStems: [] }, hosts: [{ host: 'fonts.googleapis.com', pathPattern: '^/css2?$' }],
|
|
15
|
+
endpointEnvNone: 'The application hardcodes this vendor lane host.' },
|
|
16
|
+
};
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
// Vendor wire facts; the surface is derived from the retained spec.
|
|
2
|
+
import type { DerivedManifest } from '@volter/world-core';
|
|
3
|
+
export const manifest: DerivedManifest = {
|
|
4
|
+
vendor: 'googlefonts', service: 'googlefonts', body: { json: 'always' },
|
|
5
|
+
ids: { template: '{uuid}' }, time: 'iso',
|
|
6
|
+
error: { error: { code: '{status}', message: '{message}', status: '{kind}' } },
|
|
7
|
+
readOnly: { status: 403, kind: 'PERMISSION_DENIED', message: 'Read-only World' },
|
|
8
|
+
notFound: { status: 404, kind: 'NOT_FOUND', message: 'Not Found' },
|
|
9
|
+
gap: { status: 404, kind: 'NOT_FOUND', message: 'Not Found' },
|
|
10
|
+
list: { style: 'envelope', envelope: { items: '{data}' }, limit: { param: 'limit', default: 100, max: 100 } },
|
|
11
|
+
deleted: {},
|
|
12
|
+
resources: {},
|
|
13
|
+
discovery: { twinOf: 'Google Fonts browser-selected CSS', stores: 'Published catalog and font representations in the shared googlefonts store' },
|
|
14
|
+
|
|
15
|
+
descriptor: { protocol: '3', transport: 'rest', archetype: 'crud', bin: 'world-googlefonts-css',
|
|
16
|
+
resources: [], specSource: 'css/spec/SOURCE.md', description: 'Google Fonts browser-selected CSS',
|
|
17
|
+
adoption: { sdks: [], envStems: [] }, hosts: [{ host: 'fonts.googleapis.com', pathPattern: '^/css2?$' }],
|
|
18
|
+
endpointEnvNone: 'The application hardcodes this vendor lane host.' },
|
|
19
|
+
};
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { CATALOG, CSS, cssKey, htmlError } from "./shared.js";
|
|
2
|
+
// source: spec:getStylesheet "The representation is selected for the requesting browser."
|
|
3
|
+
export async function getStylesheet(ctx) {
|
|
4
|
+
const query = new URL(ctx.call.request.url).searchParams;
|
|
5
|
+
const family = query.get('family'), subset = query.get('subset') ?? 'latin';
|
|
6
|
+
if (!family || [...query.keys()].some(k => !['family', 'subset'].includes(k)))
|
|
7
|
+
return htmlError(400, 'Bad font request');
|
|
8
|
+
const generation = ctx.row(CATALOG, 'published')?.fingerprint;
|
|
9
|
+
const key = cssKey(ctx, family, subset, ctx.call.request.headers.get('user-agent') ?? '');
|
|
10
|
+
const row = generation === undefined ? undefined : ctx.row(CSS, String(generation) + ':' + key);
|
|
11
|
+
// Where the documentation stops: no supplied representation is a named
|
|
12
|
+
// refusal, not an invented conversion or another browser's font format.
|
|
13
|
+
if (!row)
|
|
14
|
+
return htmlError(400, 'Font family or browser representation is not published');
|
|
15
|
+
const body = await ctx.blobs.get(String(row.blob));
|
|
16
|
+
if (!body)
|
|
17
|
+
return htmlError(404, 'Font stylesheet not found');
|
|
18
|
+
return new Response(Uint8Array.from(body).buffer, { headers: { 'content-type': 'text/css; charset=utf-8', 'content-length': String(body.length), 'vary': 'User-Agent' } });
|
|
19
|
+
}
|