@r8s/recipes 0.2.0 → 0.3.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 (69) hide show
  1. package/dist/app.d.ts +1 -1
  2. package/dist/app.d.ts.map +1 -1
  3. package/dist/app.js +4 -8
  4. package/dist/app.js.map +1 -1
  5. package/dist/auth.d.ts.map +1 -1
  6. package/dist/auth.js +54 -94
  7. package/dist/auth.js.map +1 -1
  8. package/dist/backup.d.ts +18 -2
  9. package/dist/backup.d.ts.map +1 -1
  10. package/dist/backup.js +54 -6
  11. package/dist/backup.js.map +1 -1
  12. package/dist/cert-provider.d.ts.map +1 -1
  13. package/dist/cert-provider.js +2 -5
  14. package/dist/cert-provider.js.map +1 -1
  15. package/dist/database.d.ts +55 -13
  16. package/dist/database.d.ts.map +1 -1
  17. package/dist/database.js +135 -58
  18. package/dist/database.js.map +1 -1
  19. package/dist/dns-provider.d.ts.map +1 -1
  20. package/dist/dns-provider.js +2 -5
  21. package/dist/dns-provider.js.map +1 -1
  22. package/dist/endpoint.d.ts +1 -1
  23. package/dist/endpoint.d.ts.map +1 -1
  24. package/dist/endpoint.js +31 -23
  25. package/dist/endpoint.js.map +1 -1
  26. package/dist/errors.d.ts +16 -0
  27. package/dist/errors.d.ts.map +1 -0
  28. package/dist/errors.js +19 -0
  29. package/dist/errors.js.map +1 -0
  30. package/dist/index.d.ts +5 -2
  31. package/dist/index.d.ts.map +1 -1
  32. package/dist/index.js +18 -5
  33. package/dist/index.js.map +1 -1
  34. package/dist/monitoring.d.ts.map +1 -1
  35. package/dist/monitoring.js +6 -13
  36. package/dist/monitoring.js.map +1 -1
  37. package/dist/platform.d.ts +3 -2
  38. package/dist/platform.d.ts.map +1 -1
  39. package/dist/platform.js +3 -2
  40. package/dist/platform.js.map +1 -1
  41. package/dist/r8s-cluster.d.ts +1 -1
  42. package/dist/r8s-cluster.d.ts.map +1 -1
  43. package/dist/r8s-cluster.js +25 -16
  44. package/dist/r8s-cluster.js.map +1 -1
  45. package/dist/s3-provider.d.ts +151 -0
  46. package/dist/s3-provider.d.ts.map +1 -0
  47. package/dist/s3-provider.js +126 -0
  48. package/dist/s3-provider.js.map +1 -0
  49. package/dist/secret-provider.d.ts +16 -7
  50. package/dist/secret-provider.d.ts.map +1 -1
  51. package/dist/secret-provider.js +80 -9
  52. package/dist/secret-provider.js.map +1 -1
  53. package/dist/static-secret.d.ts +107 -0
  54. package/dist/static-secret.d.ts.map +1 -0
  55. package/dist/static-secret.js +87 -0
  56. package/dist/static-secret.js.map +1 -0
  57. package/dist/use-operators.d.ts +7 -0
  58. package/dist/use-operators.d.ts.map +1 -0
  59. package/dist/use-operators.js +13 -0
  60. package/dist/use-operators.js.map +1 -0
  61. package/dist/web-service.d.ts +10 -2
  62. package/dist/web-service.d.ts.map +1 -1
  63. package/dist/web-service.js +54 -14
  64. package/dist/web-service.js.map +1 -1
  65. package/package.json +30 -5
  66. package/dist/operators.d.ts +0 -19
  67. package/dist/operators.d.ts.map +0 -1
  68. package/dist/operators.js +0 -30
  69. package/dist/operators.js.map +0 -1
@@ -1,4 +1,13 @@
1
- import { type SecretProvider as SecretProviderConfig } from '@r8s/core/defaults';
1
+ import { type SecretProvider as SecretProviderConfig, type SecretProvisioner } from '@r8s/core/defaults';
2
+ /**
3
+ * Provisioner resolution — THE single identity-aware point in the platform.
4
+ * Everything downstream codes against the `provision()` capability; new
5
+ * backends plug in by carrying their own provisioner on the context value
6
+ * (or by being registered here — the orchestration point).
7
+ */
8
+ export declare function provisionerForSecretProvider(provider: SecretProviderConfig | null | undefined): SecretProvisioner | undefined;
9
+ /** Can this provider provision secrets? (capability check, not identity) */
10
+ export declare function canProvisionSecrets(provider: SecretProviderConfig | null | undefined): provider is SecretProviderConfig;
2
11
  /**
3
12
  * OpenBao configuration component.
4
13
  *
@@ -60,7 +69,7 @@ export interface SecretProviderProps {
60
69
  *
61
70
  * export default (
62
71
  * <SecretProvider provider="openbao">
63
- * <Database name="app-db" />
72
+ * <Database backup={false} name="app-db" />
64
73
  * </SecretProvider>
65
74
  * )
66
75
  *
@@ -69,7 +78,7 @@ export interface SecretProviderProps {
69
78
  *
70
79
  * export default (
71
80
  * <SecretProvider provider={<OpenBao mount="secret" path="infra" authRef="custom" />}>
72
- * <Database name="app-db" />
81
+ * <Database backup={false} name="app-db" />
73
82
  * </SecretProvider>
74
83
  * )
75
84
  */
@@ -88,7 +97,7 @@ export interface SecretProviderProps {
88
97
  *
89
98
  * export default (
90
99
  * <SecretProvider provider="openbao">
91
- * <Database name="app-db" />
100
+ * <Database backup={false} name="app-db" />
92
101
  * </SecretProvider>
93
102
  * )
94
103
  *
@@ -97,7 +106,7 @@ export interface SecretProviderProps {
97
106
  *
98
107
  * export default (
99
108
  * <SecretProvider provider={<OpenBao mount="secret" path="infra" authRef="custom-auth" />}>
100
- * <Database name="app-db" />
109
+ * <Database backup={false} name="app-db" />
101
110
  * </SecretProvider>
102
111
  * )
103
112
  *
@@ -106,7 +115,7 @@ export interface SecretProviderProps {
106
115
  *
107
116
  * export default (
108
117
  * <SecretProvider provider={<Vault mount="kv" path="apps" />}>
109
- * <Database name="app-db" />
118
+ * <Database backup={false} name="app-db" />
110
119
  * </SecretProvider>
111
120
  * )
112
121
  *
@@ -115,7 +124,7 @@ export interface SecretProviderProps {
115
124
  *
116
125
  * export default (
117
126
  * <SecretProvider provider="sealed-secrets">
118
- * <Database name="app-db" />
127
+ * <Database backup={false} name="app-db" />
119
128
  * </SecretProvider>
120
129
  * )
121
130
  */
@@ -1 +1 @@
1
- {"version":3,"file":"secret-provider.d.ts","sourceRoot":"","sources":["../src/secret-provider.tsx"],"names":[],"mappings":"AACA,OAAO,EAAiB,KAAK,cAAc,IAAI,oBAAoB,EAAE,MAAM,oBAAoB,CAAA;AAI/F;;;;;;;GAOG;AACH,MAAM,WAAW,YAAY;IAC3B,6CAA6C;IAC7C,KAAK,CAAC,EAAE,MAAM,CAAA;IACd,iEAAiE;IACjE,IAAI,CAAC,EAAE,MAAM,CAAA;IACb,wCAAwC;IACxC,OAAO,CAAC,EAAE,MAAM,CAAA;IAChB,8EAA8E;IAC9E,YAAY,CAAC,EAAE,MAAM,CAAA;CACtB;AAED,wBAAgB,OAAO,CAAC,KAAK,EAAE,YAAY,GAAG,oBAAoB,CAQjE;AAED;;GAEG;AACH,MAAM,WAAW,UAAU;IACzB,2CAA2C;IAC3C,KAAK,CAAC,EAAE,MAAM,CAAA;IACd,gCAAgC;IAChC,IAAI,CAAC,EAAE,MAAM,CAAA;IACb,sCAAsC;IACtC,OAAO,CAAC,EAAE,MAAM,CAAA;IAChB,8EAA8E;IAC9E,YAAY,CAAC,EAAE,MAAM,CAAA;CACtB;AAED,wBAAgB,KAAK,CAAC,KAAK,EAAE,UAAU,GAAG,oBAAoB,CAQ7D;AAED;;GAEG;AACH,MAAM,WAAW,kBAAkB;IACjC,8EAA8E;IAC9E,SAAS,CAAC,EAAE,MAAM,CAAA;CACnB;AAED,wBAAgB,aAAa,CAAC,KAAK,EAAE,kBAAkB,GAAG,oBAAoB,CAI7E;AAED;;;;;GAKG;AACH,MAAM,WAAW,kBAAkB;CAAG;AAEtC,wBAAgB,aAAa,CAAC,KAAK,EAAE,kBAAkB,GAAG,oBAAoB,CAI7E;AAED,kDAAkD;AAClD,MAAM,MAAM,mBAAmB,GAC7B,SAAS,GAAG,OAAO,GAAG,gBAAgB,GAAG,gBAAgB,GAAG,oBAAoB,CAAA;AAElF,MAAM,WAAW,mBAAmB;IAClC;;;;;;;;;;;;;;;;;;;;OAoBG;IACH,QAAQ,EAAE,mBAAmB,CAAA;IAC7B,uBAAuB;IACvB,QAAQ,CAAC,EAAE,OAAO,CAAA;CACnB;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAyCG;AACH,wBAAgB,cAAc,CAAC,KAAK,EAAE,mBAAmB,kCA0CxD"}
1
+ {"version":3,"file":"secret-provider.d.ts","sourceRoot":"","sources":["../src/secret-provider.tsx"],"names":[],"mappings":"AACA,OAAO,EAEL,KAAK,cAAc,IAAI,oBAAoB,EAC3C,KAAK,iBAAiB,EAEvB,MAAM,oBAAoB,CAAA;AAI3B;;;;;GAKG;AACH,wBAAgB,4BAA4B,CAC1C,QAAQ,EAAE,oBAAoB,GAAG,IAAI,GAAG,SAAS,GAChD,iBAAiB,GAAG,SAAS,CAO/B;AAED,4EAA4E;AAC5E,wBAAgB,mBAAmB,CACjC,QAAQ,EAAE,oBAAoB,GAAG,IAAI,GAAG,SAAS,GAChD,QAAQ,IAAI,oBAAoB,CAElC;AA2DD;;;;;;;GAOG;AACH,MAAM,WAAW,YAAY;IAC3B,6CAA6C;IAC7C,KAAK,CAAC,EAAE,MAAM,CAAA;IACd,iEAAiE;IACjE,IAAI,CAAC,EAAE,MAAM,CAAA;IACb,wCAAwC;IACxC,OAAO,CAAC,EAAE,MAAM,CAAA;IAChB,8EAA8E;IAC9E,YAAY,CAAC,EAAE,MAAM,CAAA;CACtB;AAED,wBAAgB,OAAO,CAAC,KAAK,EAAE,YAAY,GAAG,oBAAoB,CAQjE;AAED;;GAEG;AACH,MAAM,WAAW,UAAU;IACzB,2CAA2C;IAC3C,KAAK,CAAC,EAAE,MAAM,CAAA;IACd,gCAAgC;IAChC,IAAI,CAAC,EAAE,MAAM,CAAA;IACb,sCAAsC;IACtC,OAAO,CAAC,EAAE,MAAM,CAAA;IAChB,8EAA8E;IAC9E,YAAY,CAAC,EAAE,MAAM,CAAA;CACtB;AAED,wBAAgB,KAAK,CAAC,KAAK,EAAE,UAAU,GAAG,oBAAoB,CAQ7D;AAED;;GAEG;AACH,MAAM,WAAW,kBAAkB;IACjC,8EAA8E;IAC9E,SAAS,CAAC,EAAE,MAAM,CAAA;CACnB;AAED,wBAAgB,aAAa,CAAC,KAAK,EAAE,kBAAkB,GAAG,oBAAoB,CAI7E;AAED;;;;;GAKG;AACH,MAAM,WAAW,kBAAkB;CAAG;AAEtC,wBAAgB,aAAa,CAAC,KAAK,EAAE,kBAAkB,GAAG,oBAAoB,CAI7E;AAED,kDAAkD;AAClD,MAAM,MAAM,mBAAmB,GAC7B,SAAS,GAAG,OAAO,GAAG,gBAAgB,GAAG,gBAAgB,GAAG,oBAAoB,CAAA;AAElF,MAAM,WAAW,mBAAmB;IAClC;;;;;;;;;;;;;;;;;;;;OAoBG;IACH,QAAQ,EAAE,mBAAmB,CAAA;IAC7B,uBAAuB;IACvB,QAAQ,CAAC,EAAE,OAAO,CAAA;CACnB;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAyCG;AACH,wBAAgB,cAAc,CAAC,KAAK,EAAE,mBAAmB,kCAuCxD"}
@@ -1,5 +1,7 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.provisionerForSecretProvider = provisionerForSecretProvider;
4
+ exports.canProvisionSecrets = canProvisionSecrets;
3
5
  exports.OpenBao = OpenBao;
4
6
  exports.Vault = Vault;
5
7
  exports.SealedSecrets = SealedSecrets;
@@ -8,7 +10,79 @@ exports.SecretProvider = SecretProvider;
8
10
  const core_1 = require("@r8s/core");
9
11
  const defaults_1 = require("@r8s/core/defaults");
10
12
  const defaults_2 = require("@r8s/core/defaults");
11
- const crds_1 = require("@r8s/crds");
13
+ const operator_vault_secrets_1 = require("@r8s/operator-vault-secrets");
14
+ /**
15
+ * Provisioner resolution — THE single identity-aware point in the platform.
16
+ * Everything downstream codes against the `provision()` capability; new
17
+ * backends plug in by carrying their own provisioner on the context value
18
+ * (or by being registered here — the orchestration point).
19
+ */
20
+ function provisionerForSecretProvider(provider) {
21
+ if (!provider)
22
+ return undefined;
23
+ if (typeof provider.provision === 'function')
24
+ return provider.provision;
25
+ if (provider.backend === 'vault' || provider.backend === 'openbao') {
26
+ return (req) => builtinProvisionStaticSecret(provider, req);
27
+ }
28
+ return undefined;
29
+ }
30
+ /** Can this provider provision secrets? (capability check, not identity) */
31
+ function canProvisionSecrets(provider) {
32
+ return provisionerForSecretProvider(provider) !== undefined;
33
+ }
34
+ /** Built-in Vault/OpenBao emission (VaultStaticSecret / OpenBaoStaticSecret) */
35
+ function builtinProvisionStaticSecret(provider, req) {
36
+ // Two modes: an EXHAUSTIVE bundle (keys/templates given — destination
37
+ // carries exactly those keys, excludeRaw) or a RAW SYNC (empty keys and
38
+ // no templates — destination passes the whole store entry through,
39
+ // legacy Database/operator-contract shape).
40
+ const exhaustive = Object.keys(req.keys).length > 0 || req.templates !== undefined;
41
+ const spec = {
42
+ ...(provider.backend === 'vault'
43
+ ? { vaultAuthRef: req.authRef ?? provider.authRef }
44
+ : { openbaoAuthRef: req.authRef ?? provider.authRef }),
45
+ mount: req.mount ?? provider.mount,
46
+ type: 'kv-v2',
47
+ path: req.path,
48
+ refreshAfter: req.refreshAfter ?? provider.refreshAfter ?? (exhaustive ? '1h' : undefined),
49
+ ...(req.restartTargets && req.restartTargets.length > 0
50
+ ? { rolloutRestartTargets: req.restartTargets }
51
+ : {}),
52
+ destination: exhaustive
53
+ ? {
54
+ create: true,
55
+ name: req.secretName ?? req.name,
56
+ overwrite: true,
57
+ transformation: {
58
+ excludeRaw: true,
59
+ templates: {
60
+ ...Object.fromEntries(Object.entries(req.keys).map(([dest, src]) => [
61
+ dest,
62
+ { text: `{{ .Secrets.${src} }}` },
63
+ ])),
64
+ // Raw passthrough templates (literals, composed templates) win
65
+ // over key-mapped entries on collision
66
+ ...Object.fromEntries(Object.entries(req.templates ?? {}).map(([dest, tpl]) => [dest, { text: tpl }])),
67
+ },
68
+ },
69
+ }
70
+ : { create: true, name: req.secretName ?? req.name },
71
+ };
72
+ return provider.backend === 'vault'
73
+ ? (0, core_1.jsx)('VaultStaticSecret', {
74
+ apiVersion: 'secrets.hashicorp.com/v1beta1',
75
+ kind: 'VaultStaticSecret',
76
+ metadata: { name: req.name, namespace: req.namespace },
77
+ spec,
78
+ })
79
+ : (0, core_1.jsx)('OpenBaoStaticSecret', {
80
+ apiVersion: 'secrets.openbao.org/v1beta1',
81
+ kind: 'OpenBaoStaticSecret',
82
+ metadata: { name: req.name, namespace: req.namespace },
83
+ spec,
84
+ });
85
+ }
12
86
  function OpenBao(props) {
13
87
  return {
14
88
  backend: 'openbao',
@@ -48,7 +122,7 @@ function ManualSecrets(props) {
48
122
  *
49
123
  * export default (
50
124
  * <SecretProvider provider="openbao">
51
- * <Database name="app-db" />
125
+ * <Database backup={false} name="app-db" />
52
126
  * </SecretProvider>
53
127
  * )
54
128
  *
@@ -57,7 +131,7 @@ function ManualSecrets(props) {
57
131
  *
58
132
  * export default (
59
133
  * <SecretProvider provider={<OpenBao mount="secret" path="infra" authRef="custom-auth" />}>
60
- * <Database name="app-db" />
134
+ * <Database backup={false} name="app-db" />
61
135
  * </SecretProvider>
62
136
  * )
63
137
  *
@@ -66,7 +140,7 @@ function ManualSecrets(props) {
66
140
  *
67
141
  * export default (
68
142
  * <SecretProvider provider={<Vault mount="kv" path="apps" />}>
69
- * <Database name="app-db" />
143
+ * <Database backup={false} name="app-db" />
70
144
  * </SecretProvider>
71
145
  * )
72
146
  *
@@ -75,7 +149,7 @@ function ManualSecrets(props) {
75
149
  *
76
150
  * export default (
77
151
  * <SecretProvider provider="sealed-secrets">
78
- * <Database name="app-db" />
152
+ * <Database backup={false} name="app-db" />
79
153
  * </SecretProvider>
80
154
  * )
81
155
  */
@@ -115,10 +189,7 @@ function SecretProvider(props) {
115
189
  const resources = [];
116
190
  // Declare VSO for vault/openbao
117
191
  if (config.backend === 'vault' || config.backend === 'openbao') {
118
- const hasVSO = sharedOperators.some((op) => op.name === 'vault-secrets-operator');
119
- if (!hasVSO) {
120
- resources.push((0, core_1.declareOperator)(crds_1.operators['vault-secrets-operator']()));
121
- }
192
+ resources.push(...(0, operator_vault_secrets_1.declareIfMissing)(sharedOperators));
122
193
  }
123
194
  return (0, core_1.jsx)(core_1.Fragment, {
124
195
  children: [...resources, (0, core_1.jsx)(defaults_1.SecretContext.Provider, { value: config, children })],
@@ -1 +1 @@
1
- {"version":3,"file":"secret-provider.js","sourceRoot":"","sources":["../src/secret-provider.tsx"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"secret-provider.js","sourceRoot":"","sources":["../src/secret-provider.tsx"],"names":[],"mappings":";;AAgBA,oEASC;AAGD,kDAIC;AA8ED,0BAQC;AAgBD,sBAQC;AAUD,sCAIC;AAUD,sCAIC;AA2ED,wCAuCC;AA5RD,oCAAsE;AACtE,iDAK2B;AAC3B,iDAAoD;AACpD,wEAA8D;AAE9D;;;;;GAKG;AACH,SAAgB,4BAA4B,CAC1C,QAAiD;IAEjD,IAAI,CAAC,QAAQ;QAAE,OAAO,SAAS,CAAA;IAC/B,IAAI,OAAO,QAAQ,CAAC,SAAS,KAAK,UAAU;QAAE,OAAO,QAAQ,CAAC,SAAS,CAAA;IACvE,IAAI,QAAQ,CAAC,OAAO,KAAK,OAAO,IAAI,QAAQ,CAAC,OAAO,KAAK,SAAS,EAAE,CAAC;QACnE,OAAO,CAAC,GAAG,EAAE,EAAE,CAAC,4BAA4B,CAAC,QAAQ,EAAE,GAAG,CAAC,CAAA;IAC7D,CAAC;IACD,OAAO,SAAS,CAAA;AAClB,CAAC;AAED,4EAA4E;AAC5E,SAAgB,mBAAmB,CACjC,QAAiD;IAEjD,OAAO,4BAA4B,CAAC,QAAQ,CAAC,KAAK,SAAS,CAAA;AAC7D,CAAC;AAED,gFAAgF;AAChF,SAAS,4BAA4B,CAAC,QAA8B,EAAE,GAAwB;IAC5F,sEAAsE;IACtE,wEAAwE;IACxE,mEAAmE;IACnE,4CAA4C;IAC5C,MAAM,UAAU,GAAG,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC,MAAM,GAAG,CAAC,IAAI,GAAG,CAAC,SAAS,KAAK,SAAS,CAAA;IAClF,MAAM,IAAI,GAAG;QACX,GAAG,CAAC,QAAQ,CAAC,OAAO,KAAK,OAAO;YAC9B,CAAC,CAAC,EAAE,YAAY,EAAE,GAAG,CAAC,OAAO,IAAI,QAAQ,CAAC,OAAO,EAAE;YACnD,CAAC,CAAC,EAAE,cAAc,EAAE,GAAG,CAAC,OAAO,IAAI,QAAQ,CAAC,OAAO,EAAE,CAAC;QACxD,KAAK,EAAE,GAAG,CAAC,KAAK,IAAI,QAAQ,CAAC,KAAK;QAClC,IAAI,EAAE,OAAgB;QACtB,IAAI,EAAE,GAAG,CAAC,IAAI;QACd,YAAY,EAAE,GAAG,CAAC,YAAY,IAAI,QAAQ,CAAC,YAAY,IAAI,CAAC,UAAU,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,SAAS,CAAC;QAC1F,GAAG,CAAC,GAAG,CAAC,cAAc,IAAI,GAAG,CAAC,cAAc,CAAC,MAAM,GAAG,CAAC;YACrD,CAAC,CAAC,EAAE,qBAAqB,EAAE,GAAG,CAAC,cAAc,EAAE;YAC/C,CAAC,CAAC,EAAE,CAAC;QACP,WAAW,EAAE,UAAU;YACrB,CAAC,CAAC;gBACE,MAAM,EAAE,IAAI;gBACZ,IAAI,EAAE,GAAG,CAAC,UAAU,IAAI,GAAG,CAAC,IAAI;gBAChC,SAAS,EAAE,IAAI;gBACf,cAAc,EAAE;oBACd,UAAU,EAAE,IAAI;oBAChB,SAAS,EAAE;wBACT,GAAG,MAAM,CAAC,WAAW,CACnB,MAAM,CAAC,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,IAAI,EAAE,GAAG,CAAC,EAAE,EAAE,CAAC;4BAC5C,IAAI;4BACJ,EAAE,IAAI,EAAE,eAAe,GAAG,KAAK,EAAE;yBAClC,CAAC,CACH;wBACD,+DAA+D;wBAC/D,uCAAuC;wBACvC,GAAG,MAAM,CAAC,WAAW,CACnB,MAAM,CAAC,OAAO,CAAC,GAAG,CAAC,SAAS,IAAI,EAAE,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,IAAI,EAAE,GAAG,CAAC,EAAE,EAAE,CAAC,CAAC,IAAI,EAAE,EAAE,IAAI,EAAE,GAAG,EAAE,CAAC,CAAC,CAChF;qBACF;iBACF;aACF;YACH,CAAC,CAAC,EAAE,MAAM,EAAE,IAAI,EAAE,IAAI,EAAE,GAAG,CAAC,UAAU,IAAI,GAAG,CAAC,IAAI,EAAE;KACvD,CAAA;IACD,OAAO,QAAQ,CAAC,OAAO,KAAK,OAAO;QACjC,CAAC,CAAC,IAAA,UAAG,EAAC,mBAAmB,EAAE;YACvB,UAAU,EAAE,+BAA+B;YAC3C,IAAI,EAAE,mBAAmB;YACzB,QAAQ,EAAE,EAAE,IAAI,EAAE,GAAG,CAAC,IAAI,EAAE,SAAS,EAAE,GAAG,CAAC,SAAS,EAAE;YACtD,IAAI;SACL,CAAC;QACJ,CAAC,CAAC,IAAA,UAAG,EAAC,qBAAqB,EAAE;YACzB,UAAU,EAAE,6BAA6B;YACzC,IAAI,EAAE,qBAAqB;YAC3B,QAAQ,EAAE,EAAE,IAAI,EAAE,GAAG,CAAC,IAAI,EAAE,SAAS,EAAE,GAAG,CAAC,SAAS,EAAE;YACtD,IAAI;SACL,CAAC,CAAA;AACR,CAAC;AAqBD,SAAgB,OAAO,CAAC,KAAmB;IACzC,OAAO;QACL,OAAO,EAAE,SAAS;QAClB,KAAK,EAAE,KAAK,CAAC,KAAK;QAClB,IAAI,EAAE,KAAK,CAAC,IAAI;QAChB,OAAO,EAAE,KAAK,CAAC,OAAO;QACtB,GAAG,CAAC,KAAK,CAAC,YAAY,IAAI,EAAE,YAAY,EAAE,KAAK,CAAC,YAAY,EAAE,CAAC;KAChE,CAAA;AACH,CAAC;AAgBD,SAAgB,KAAK,CAAC,KAAiB;IACrC,OAAO;QACL,OAAO,EAAE,OAAO;QAChB,KAAK,EAAE,KAAK,CAAC,KAAK;QAClB,IAAI,EAAE,KAAK,CAAC,IAAI;QAChB,OAAO,EAAE,KAAK,CAAC,OAAO;QACtB,GAAG,CAAC,KAAK,CAAC,YAAY,IAAI,EAAE,YAAY,EAAE,KAAK,CAAC,YAAY,EAAE,CAAC;KAChE,CAAA;AACH,CAAC;AAUD,SAAgB,aAAa,CAAC,KAAyB;IACrD,OAAO;QACL,OAAO,EAAE,gBAAgB;KAC1B,CAAA;AACH,CAAC;AAUD,SAAgB,aAAa,CAAC,KAAyB;IACrD,OAAO;QACL,OAAO,EAAE,gBAAgB;KAC1B,CAAA;AACH,CAAC;AAiCD;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAyCG;AACH,SAAgB,cAAc,CAAC,KAA0B;IACvD,MAAM,EAAE,QAAQ,EAAE,QAAQ,EAAE,GAAG,KAAK,CAAA;IAEpC,MAAM,eAAe,GAAG,IAAA,iBAAU,EAAC,0BAAe,CAAC,CAAA;IAEnD,0BAA0B;IAC1B,IAAI,MAA4B,CAAA;IAChC,IAAI,OAAO,QAAQ,KAAK,QAAQ,EAAE,CAAC;QACjC,MAAM,GAAG,EAAE,OAAO,EAAE,QAAQ,EAAE,CAAA;IAChC,CAAC;SAAM,IAAI,SAAS,IAAI,QAAQ,EAAE,CAAC;QACjC,MAAM,GAAG,QAAQ,CAAA;IACnB,CAAC;SAAM,IAAI,QAAQ,IAAI,OAAO,QAAQ,KAAK,QAAQ,IAAI,MAAM,IAAI,QAAQ,EAAE,CAAC;QAC1E,sDAAsD;QACtD,MAAM,SAAS,GAAI,QAAgB,CAAC,IAAI,CAAA;QACxC,IAAI,SAAS,KAAK,OAAO,EAAE,CAAC;YAC1B,MAAM,GAAG,OAAO,CAAE,QAAgB,CAAC,KAAK,CAAC,CAAA;QAC3C,CAAC;aAAM,IAAI,SAAS,KAAK,KAAK,EAAE,CAAC;YAC/B,MAAM,GAAG,KAAK,CAAE,QAAgB,CAAC,KAAK,CAAC,CAAA;QACzC,CAAC;aAAM,IAAI,SAAS,KAAK,aAAa,EAAE,CAAC;YACvC,MAAM,GAAG,aAAa,CAAE,QAAgB,CAAC,KAAK,CAAC,CAAA;QACjD,CAAC;aAAM,IAAI,SAAS,KAAK,aAAa,EAAE,CAAC;YACvC,MAAM,GAAG,aAAa,CAAE,QAAgB,CAAC,KAAK,CAAC,CAAA;QACjD,CAAC;aAAM,CAAC;YACN,MAAM,IAAI,KAAK,CAAC,sCAAsC,SAAS,CAAC,IAAI,IAAI,SAAS,EAAE,CAAC,CAAA;QACtF,CAAC;IACH,CAAC;SAAM,CAAC;QACN,MAAM,IAAI,KAAK,CAAC,4BAA4B,IAAI,CAAC,SAAS,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAA;IACzE,CAAC;IAED,MAAM,SAAS,GAA6B,EAAE,CAAA;IAE9C,gCAAgC;IAChC,IAAI,MAAM,CAAC,OAAO,KAAK,OAAO,IAAI,MAAM,CAAC,OAAO,KAAK,SAAS,EAAE,CAAC;QAC/D,SAAS,CAAC,IAAI,CAAC,GAAG,IAAA,yCAAgB,EAAC,eAAe,CAAC,CAAC,CAAA;IACtD,CAAC;IAED,OAAO,IAAA,UAAG,EAAC,eAAQ,EAAE;QACnB,QAAQ,EAAE,CAAC,GAAG,SAAS,EAAE,IAAA,UAAG,EAAC,wBAAa,CAAC,QAAQ,EAAE,EAAE,KAAK,EAAE,MAAM,EAAE,QAAQ,EAAE,CAAC,CAAC;KACnF,CAAC,CAAA;AACJ,CAAC"}
@@ -0,0 +1,107 @@
1
+ export interface StaticSecretProps {
2
+ /**
3
+ * Resource name (also the default for the provisioned Kubernetes
4
+ * Secret's name — override with secretName).
5
+ */
6
+ name: string;
7
+ /** Kubernetes namespace (inherited from Platform context when omitted) */
8
+ namespace?: string;
9
+ /**
10
+ * Vault/OpenBao KV v2 path holding the source keys, e.g. 'outline/app'.
11
+ * Build it from the provider's base path when composing:
12
+ * `${secretProvider.path}/myapp/credentials`.
13
+ */
14
+ path: string;
15
+ /**
16
+ * Destination→source key mapping. The destination carries env-case
17
+ * names consumed by the app; the vault/store keys stay snake_case:
18
+ * keys={{ SECRET_KEY: 'secret_key', UTILS_SECRET: 'utils_secret' }}
19
+ * A string array is shorthand for identity mappings ({ KEY: 'KEY' }).
20
+ *
21
+ * Rendered as destination.transformation.templates + excludeRaw —
22
+ * the destination holds ONLY these keys.
23
+ */
24
+ keys: Record<string, string> | string[];
25
+ /**
26
+ * Raw Go-template passthrough merged AFTER the keys mapping — for
27
+ * advanced bundles needing literals or composed templates
28
+ * (e.g. `AWS_ENDPOINTS: 'https://s3.berget.cloud'`). Passthrough wins
29
+ * over key-mapped entries on collision.
30
+ */
31
+ templates?: Record<string, string>;
32
+ /** Provisioned Kubernetes Secret name (defaults to name) */
33
+ secretName?: string;
34
+ /**
35
+ * Re-sync interval rendered as refreshAfter. Defaults to the provider's
36
+ * refreshAfter, else '1h'.
37
+ */
38
+ refreshAfter?: string;
39
+ /**
40
+ * Workloads restarted after rotation (rolloutRestartTargets). Pass the
41
+ * workloads consuming these values so a rotation actually takes effect —
42
+ * pod env vars do not update in place.
43
+ *
44
+ * Deliberately has no default: some consumers read the Secret at use
45
+ * time (e.g. CNPG barman backup credentials are read when a backup
46
+ * runs, and the Cluster CRD is not a supported restart target), so an
47
+ * automatic restart is wrong for them.
48
+ */
49
+ restart?: {
50
+ kind?: string;
51
+ name: string;
52
+ apiVersion?: string;
53
+ }[];
54
+ /**
55
+ * Auth reference override (defaults to the provider's authRef).
56
+ * Rendered as vaultAuthRef / openbaoAuthRef per backend.
57
+ */
58
+ authRef?: string;
59
+ }
60
+ /**
61
+ * StaticSecret — provision a Kubernetes Secret from Vault/OpenBao,
62
+ * with rotation semantics that actually reach the workloads.
63
+ *
64
+ * Wraps VaultStaticSecret / OpenBaoStaticSecret with the platform's
65
+ * conventions baked in:
66
+ * - snake_case source keys templated to env-case destination keys
67
+ * (excludeRaw: only the declared keys land in the Secret)
68
+ * - destination create + overwrite (idempotent sync)
69
+ * - hourly refresh by default, inheriting the provider's refreshAfter
70
+ * - explicit, per-bundle restart semantics (app creds restart pods;
71
+ * backup creds read at use time never restart)
72
+ *
73
+ * Requires an active secrets backend (openbao or vault) — passive
74
+ * backends (manual-secrets, sealed-secrets) cannot provision: reference
75
+ * a pre-created Secret instead.
76
+ *
77
+ * @example
78
+ * import { Platform, StaticSecret } from '@r8s/recipes'
79
+ *
80
+ * export default (
81
+ * <Platform secrets={{ backend: 'openbao', mount: 'kv', path: 'apps' }}>
82
+ * <StaticSecret
83
+ * name="myapp-secrets"
84
+ * path="myapp/app"
85
+ * keys={{
86
+ * SECRET_KEY: 'secret_key',
87
+ * OIDC_CLIENT_ID: 'oidc_client_id',
88
+ * OIDC_CLIENT_SECRET: 'oidc_client_secret',
89
+ * }}
90
+ * restart={[{ kind: 'Deployment', name: 'myapp' }]}
91
+ * />
92
+ * </Platform>
93
+ * )
94
+ *
95
+ * @example
96
+ * import { Platform, StaticSecret } from '@r8s/recipes'
97
+ *
98
+ * // backup creds: read at use time — never restart workloads
99
+ * export default (
100
+ * <Platform secrets={{ backend: 'openbao', mount: 'kv', path: 'apps' }}>
101
+ * <StaticSecret name="myapp-backup-creds" path="rustfs/myapp"
102
+ * keys={['accesskey', 'secretkey']} />
103
+ * </Platform>
104
+ * )
105
+ */
106
+ export declare function StaticSecret(props: StaticSecretProps): import("@r8s/core").r8sElement;
107
+ //# sourceMappingURL=static-secret.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"static-secret.d.ts","sourceRoot":"","sources":["../src/static-secret.tsx"],"names":[],"mappings":"AAIA,MAAM,WAAW,iBAAiB;IAChC;;;OAGG;IACH,IAAI,EAAE,MAAM,CAAA;IACZ,0EAA0E;IAC1E,SAAS,CAAC,EAAE,MAAM,CAAA;IAClB;;;;OAIG;IACH,IAAI,EAAE,MAAM,CAAA;IACZ;;;;;;;;OAQG;IACH,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,GAAG,MAAM,EAAE,CAAA;IACvC;;;;;OAKG;IACH,SAAS,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;IAClC,4DAA4D;IAC5D,UAAU,CAAC,EAAE,MAAM,CAAA;IACnB;;;OAGG;IACH,YAAY,CAAC,EAAE,MAAM,CAAA;IACrB;;;;;;;;;OASG;IACH,OAAO,CAAC,EAAE;QAAE,IAAI,CAAC,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAC;QAAC,UAAU,CAAC,EAAE,MAAM,CAAA;KAAE,EAAE,CAAA;IAChE;;;OAGG;IACH,OAAO,CAAC,EAAE,MAAM,CAAA;CACjB;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA6CG;AACH,wBAAgB,YAAY,CAAC,KAAK,EAAE,iBAAiB,kCAoDpD"}
@@ -0,0 +1,87 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.StaticSecret = StaticSecret;
4
+ const core_1 = require("@r8s/core");
5
+ const defaults_1 = require("@r8s/core/defaults");
6
+ const secret_provider_1 = require("./secret-provider");
7
+ /**
8
+ * StaticSecret — provision a Kubernetes Secret from Vault/OpenBao,
9
+ * with rotation semantics that actually reach the workloads.
10
+ *
11
+ * Wraps VaultStaticSecret / OpenBaoStaticSecret with the platform's
12
+ * conventions baked in:
13
+ * - snake_case source keys templated to env-case destination keys
14
+ * (excludeRaw: only the declared keys land in the Secret)
15
+ * - destination create + overwrite (idempotent sync)
16
+ * - hourly refresh by default, inheriting the provider's refreshAfter
17
+ * - explicit, per-bundle restart semantics (app creds restart pods;
18
+ * backup creds read at use time never restart)
19
+ *
20
+ * Requires an active secrets backend (openbao or vault) — passive
21
+ * backends (manual-secrets, sealed-secrets) cannot provision: reference
22
+ * a pre-created Secret instead.
23
+ *
24
+ * @example
25
+ * import { Platform, StaticSecret } from '@r8s/recipes'
26
+ *
27
+ * export default (
28
+ * <Platform secrets={{ backend: 'openbao', mount: 'kv', path: 'apps' }}>
29
+ * <StaticSecret
30
+ * name="myapp-secrets"
31
+ * path="myapp/app"
32
+ * keys={{
33
+ * SECRET_KEY: 'secret_key',
34
+ * OIDC_CLIENT_ID: 'oidc_client_id',
35
+ * OIDC_CLIENT_SECRET: 'oidc_client_secret',
36
+ * }}
37
+ * restart={[{ kind: 'Deployment', name: 'myapp' }]}
38
+ * />
39
+ * </Platform>
40
+ * )
41
+ *
42
+ * @example
43
+ * import { Platform, StaticSecret } from '@r8s/recipes'
44
+ *
45
+ * // backup creds: read at use time — never restart workloads
46
+ * export default (
47
+ * <Platform secrets={{ backend: 'openbao', mount: 'kv', path: 'apps' }}>
48
+ * <StaticSecret name="myapp-backup-creds" path="rustfs/myapp"
49
+ * keys={['accesskey', 'secretkey']} />
50
+ * </Platform>
51
+ * )
52
+ */
53
+ function StaticSecret(props) {
54
+ const { name, namespace: namespaceProp, path, keys, templates, secretName, refreshAfter, restart, authRef, } = props;
55
+ const secretProvider = (0, core_1.useContext)(defaults_1.SecretContext);
56
+ const namespace = (0, defaults_1.useNamespace)(namespaceProp);
57
+ const provisioner = (0, secret_provider_1.provisionerForSecretProvider)(secretProvider);
58
+ if (!provisioner) {
59
+ throw new Error(`StaticSecret "${name}" requires a provisioning secrets backend (openbao, vault,\n` +
60
+ `or any provider carrying a provision() hook).\n` +
61
+ `\n` +
62
+ `Fix: configure a backend on the Platform:\n` +
63
+ ` <Platform secrets={{ backend: 'openbao', mount: 'kv', path: 'apps' }}>\n` +
64
+ ` <StaticSecret name="${name}" path="${path}" keys={...} />\n` +
65
+ ` </Platform>\n` +
66
+ `\n` +
67
+ `On passive backends (manual-secrets, sealed-secrets, kubernetes), create the Secret\n` +
68
+ `out of band and reference it directly instead of rendering this component.`);
69
+ }
70
+ const mapping = Object.fromEntries((Array.isArray(keys) ? keys.map((k) => [k, k]) : Object.entries(keys)));
71
+ // Default missing fields (consistent with Database/WebService restart
72
+ // target conventions)
73
+ const restartTargets = restart?.map((t) => ({ kind: 'Deployment', ...t }));
74
+ const el = provisioner({
75
+ name,
76
+ namespace,
77
+ path,
78
+ keys: mapping,
79
+ templates,
80
+ secretName,
81
+ authRef,
82
+ refreshAfter,
83
+ restartTargets,
84
+ });
85
+ return Array.isArray(el) ? (0, core_1.jsx)(core_1.Fragment, { children: el }) : el;
86
+ }
87
+ //# sourceMappingURL=static-secret.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"static-secret.js","sourceRoot":"","sources":["../src/static-secret.tsx"],"names":[],"mappings":";;AA0GA,oCAoDC;AA9JD,oCAAqD;AACrD,iDAAgE;AAChE,uDAAgE;AA0DhE;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA6CG;AACH,SAAgB,YAAY,CAAC,KAAwB;IACnD,MAAM,EACJ,IAAI,EACJ,SAAS,EAAE,aAAa,EACxB,IAAI,EACJ,IAAI,EACJ,SAAS,EACT,UAAU,EACV,YAAY,EACZ,OAAO,EACP,OAAO,GACR,GAAG,KAAK,CAAA;IAET,MAAM,cAAc,GAAG,IAAA,iBAAU,EAAC,wBAAa,CAAC,CAAA;IAChD,MAAM,SAAS,GAAG,IAAA,uBAAY,EAAC,aAAa,CAAC,CAAA;IAC7C,MAAM,WAAW,GAAG,IAAA,8CAA4B,EAAC,cAAc,CAAC,CAAA;IAEhE,IAAI,CAAC,WAAW,EAAE,CAAC;QACjB,MAAM,IAAI,KAAK,CACb,iBAAiB,IAAI,8DAA8D;YACjF,iDAAiD;YACjD,IAAI;YACJ,6CAA6C;YAC7C,4EAA4E;YAC5E,2BAA2B,IAAI,WAAW,IAAI,mBAAmB;YACjE,iBAAiB;YACjB,IAAI;YACJ,uFAAuF;YACvF,4EAA4E,CAC/E,CAAA;IACH,CAAC;IAED,MAAM,OAAO,GAA2B,MAAM,CAAC,WAAW,CACxD,CAAC,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,OAAO,CAAC,IAAI,CAAC,CAAuB,CAC7F,CAAA;IAED,sEAAsE;IACtE,sBAAsB;IACtB,MAAM,cAAc,GAAG,OAAO,EAAE,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,EAAE,IAAI,EAAE,YAAY,EAAE,GAAG,CAAC,EAAE,CAAC,CAAC,CAAA;IAE1E,MAAM,EAAE,GAAG,WAAW,CAAC;QACrB,IAAI;QACJ,SAAS;QACT,IAAI;QACJ,IAAI,EAAE,OAAO;QACb,SAAS;QACT,UAAU;QACV,OAAO;QACP,YAAY;QACZ,cAAc;KACf,CAAC,CAAA;IACF,OAAO,KAAK,CAAC,OAAO,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,IAAA,UAAG,EAAC,eAAQ,EAAE,EAAE,QAAQ,EAAE,EAAE,EAAE,CAAC,CAAC,CAAC,CAAE,EAA6B,CAAA;AAC7F,CAAC"}
@@ -0,0 +1,7 @@
1
+ import type { Operator } from '@r8s/k8s-types';
2
+ /**
3
+ * Read the operators the surrounding Platform already provides — the
4
+ * dedupe-seed shared with every consumer's `declareIfMissing`.
5
+ */
6
+ export declare function useOperators(): Operator[];
7
+ //# sourceMappingURL=use-operators.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"use-operators.d.ts","sourceRoot":"","sources":["../src/use-operators.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,gBAAgB,CAAA;AAE9C;;;GAGG;AACH,wBAAgB,YAAY,IAAI,QAAQ,EAAE,CAEzC"}
@@ -0,0 +1,13 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.useOperators = useOperators;
4
+ const core_1 = require("@r8s/core");
5
+ const defaults_1 = require("@r8s/core/defaults");
6
+ /**
7
+ * Read the operators the surrounding Platform already provides — the
8
+ * dedupe-seed shared with every consumer's `declareIfMissing`.
9
+ */
10
+ function useOperators() {
11
+ return (0, core_1.useContext)(defaults_1.OperatorContext);
12
+ }
13
+ //# sourceMappingURL=use-operators.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"use-operators.js","sourceRoot":"","sources":["../src/use-operators.ts"],"names":[],"mappings":";;AAQA,oCAEC;AAVD,oCAAsC;AACtC,iDAAoD;AAGpD;;;GAGG;AACH,SAAgB,YAAY;IAC1B,OAAO,IAAA,iBAAU,EAAC,0BAAe,CAAC,CAAA;AACpC,CAAC"}
@@ -100,7 +100,11 @@ export interface WebServiceProps {
100
100
  tolerations?: Record<string, unknown>[];
101
101
  /** Pod topologySpreadConstraints (spread replicas across nodes) */
102
102
  topologySpreadConstraints?: Record<string, unknown>[];
103
- /** Deployment update strategy — 'Recreate' for RWO-volume/migration apps */
103
+ /**
104
+ * Deployment update strategy ('Recreate' for RWO-volume/migration apps).
105
+ * Default: 'Recreate' when the pod mounts a PVC volume and replicas=1
106
+ * (RollingUpdate would deadlock on the single-attach volume).
107
+ */
104
108
  strategy?: 'Recreate' | 'RollingUpdate' | {
105
109
  type: string;
106
110
  rollingUpdate?: {
@@ -130,7 +134,11 @@ export interface WebServiceProps {
130
134
  } & Record<string, unknown>)[];
131
135
  /** Container lifecycle hooks (e.g. { preStop: { exec: { command: [...] } } }) */
132
136
  lifecycle?: Record<string, unknown>;
133
- /** Image pull policy (defaults to 'Always') */
137
+ /**
138
+ * Image pull policy. Default depends on the tag: floating tags
139
+ * (latest/main/master/dev/edge/head/nightly/canary) get 'Always', pinned
140
+ * tags and digests get 'IfNotPresent' (immutable — pointless to re-pull).
141
+ */
134
142
  imagePullPolicy?: 'Always' | 'IfNotPresent' | 'Never';
135
143
  /** Names of Secrets used to pull private registry images */
136
144
  imagePullSecrets?: string[];
@@ -1 +1 @@
1
- {"version":3,"file":"web-service.d.ts","sourceRoot":"","sources":["../src/web-service.tsx"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"web-service.d.ts","sourceRoot":"","sources":["../src/web-service.tsx"],"names":[],"mappings":"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"}
@@ -3,7 +3,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.WebService = WebService;
4
4
  const core_1 = require("@r8s/core");
5
5
  const defaults_1 = require("@r8s/core/defaults");
6
- const operators_1 = require("./operators");
6
+ const operator_vault_secrets_1 = require("@r8s/operator-vault-secrets");
7
7
  /**
8
8
  * Simple web service (backend or frontend).
9
9
  *
@@ -42,7 +42,7 @@ const operators_1 = require("./operators");
42
42
  * )
43
43
  */
44
44
  function WebService(props) {
45
- const { name, namespace = 'default', image, port = 3000, replicas = 2, probes, env = {}, secrets = {}, vault = {}, command, args, rawEnv = [], resources, securityContext, podSecurityContext, tolerations, topologySpreadConstraints, strategy, volumes, volumeMounts, initContainers, lifecycle, imagePullPolicy = 'Always', imagePullSecrets, } = props;
45
+ const { name, namespace: namespaceProp, image, port = 3000, replicas = 2, probes, env = {}, secrets = {}, vault = {}, command, args, rawEnv = [], resources, securityContext, podSecurityContext, tolerations, topologySpreadConstraints, strategy, volumes, volumeMounts, initContainers, lifecycle, imagePullPolicy, imagePullSecrets, } = props;
46
46
  const buildProbe = (spec, fallbackPath) => {
47
47
  if (spec === null)
48
48
  return undefined;
@@ -51,18 +51,57 @@ function WebService(props) {
51
51
  const initialDelaySeconds = spec.initialDelaySeconds ?? 10;
52
52
  const periodSeconds = spec.periodSeconds ?? 10;
53
53
  if (spec.tcp) {
54
- return { tcpSocket: { port: spec.port ?? port }, initialDelaySeconds, periodSeconds };
54
+ return {
55
+ tcpSocket: { port: spec.port ?? port },
56
+ initialDelaySeconds,
57
+ periodSeconds,
58
+ // !== undefined (not truthy): an explicit 0 must surface as-is so
59
+ // Kubernetes validation fails loudly instead of silently reverting
60
+ // to the default
61
+ ...(spec.failureThreshold !== undefined && { failureThreshold: spec.failureThreshold }),
62
+ };
55
63
  }
56
64
  return {
57
65
  httpGet: { path: spec.path ?? fallbackPath, port: spec.port ?? port },
58
66
  initialDelaySeconds,
59
67
  periodSeconds,
60
- ...(spec.failureThreshold && { failureThreshold: spec.failureThreshold }),
68
+ ...(spec.failureThreshold !== undefined && { failureThreshold: spec.failureThreshold }),
61
69
  };
62
70
  };
63
71
  const livenessProbe = buildProbe(probes?.liveness, '/health');
64
72
  const readinessProbe = buildProbe(probes?.readiness, '/ready');
65
73
  const startupProbe = buildProbe(probes?.startup ?? null, '/health');
74
+ // --- Safe defaults derived from the image and storage shape -------------
75
+ // imagePullPolicy: a floating tag must be re-pulled (Always); a pinned tag
76
+ // (or digest) is immutable, so IfNotPresent avoids pointless pulls and
77
+ // makes deploys robust when a registry is slow/unreachable. Explicit prop
78
+ // always wins. Floating set covers the conventional mutables.
79
+ const imageLeaf = image.slice(image.lastIndexOf('/') + 1);
80
+ const imageTag = imageLeaf.includes('@')
81
+ ? imageLeaf.slice(imageLeaf.indexOf('@') + 1)
82
+ : imageLeaf.includes(':')
83
+ ? imageLeaf.slice(imageLeaf.indexOf(':') + 1)
84
+ : 'latest';
85
+ const FLOATING_TAGS = new Set([
86
+ 'latest',
87
+ 'main',
88
+ 'master',
89
+ 'dev',
90
+ 'edge',
91
+ 'head',
92
+ 'nightly',
93
+ 'canary',
94
+ ]);
95
+ const pullPolicy = imagePullPolicy ??
96
+ (!imageLeaf.includes('@') && FLOATING_TAGS.has(imageTag.toLowerCase())
97
+ ? 'Always'
98
+ : 'IfNotPresent');
99
+ // strategy: RollingUpdate + a ReadWriteOnce PVC + replicas=1 deadlocks
100
+ // (the new pod cannot attach the volume until the old releases it), and
101
+ // in-place DB-migration apps (n8n, outline) must not run two versions at
102
+ // once. Recreate is always safe at replicas=1 — there is already no HA.
103
+ const hasPvcVolume = (volumes ?? []).some((v) => 'persistentVolumeClaim' in v);
104
+ const derivedStrategy = strategy ?? (hasPvcVolume && replicas === 1 ? 'Recreate' : undefined);
66
105
  const envVars = [];
67
106
  const vaultResources = [];
68
107
  // Secrets from Kubernetes Secrets — pushed before plain env vars so
@@ -89,6 +128,7 @@ function WebService(props) {
89
128
  envVars.push({ name: key, value });
90
129
  }
91
130
  // Vault secrets — create VaultStaticSecret objects
131
+ const namespace = (0, defaults_1.useNamespace)(namespaceProp);
92
132
  const platformSecrets = (0, core_1.useContext)(defaults_1.SecretContext);
93
133
  for (const [envName, ref] of Object.entries(vault)) {
94
134
  const secretName = `${name}-${envName.toLowerCase().replace(/_/g, '-')}-vault`;
@@ -155,10 +195,7 @@ function WebService(props) {
155
195
  // Declare Vault Secrets Operator if vault secrets are used
156
196
  if (Object.keys(vault).length > 0) {
157
197
  const sharedOperators = (0, core_1.useContext)(defaults_1.OperatorContext);
158
- const hasVSO = sharedOperators.some((op) => op.name === 'vault-secrets-operator');
159
- if (!hasVSO) {
160
- vaultResources.push((0, core_1.declareOperator)((0, operators_1.vaultSecretsOperator)()));
161
- }
198
+ vaultResources.push(...(0, operator_vault_secrets_1.declareIfMissing)(sharedOperators));
162
199
  }
163
200
  const deployment = {
164
201
  apiVersion: 'apps/v1',
@@ -166,8 +203,8 @@ function WebService(props) {
166
203
  metadata: { name, namespace, labels: { app: name } },
167
204
  spec: {
168
205
  replicas,
169
- ...(strategy && {
170
- strategy: typeof strategy === 'string' ? { type: strategy } : strategy,
206
+ ...(derivedStrategy && {
207
+ strategy: typeof derivedStrategy === 'string' ? { type: derivedStrategy } : derivedStrategy,
171
208
  }),
172
209
  selector: { matchLabels: { app: name } },
173
210
  template: {
@@ -187,7 +224,7 @@ function WebService(props) {
187
224
  {
188
225
  name: 'app',
189
226
  image,
190
- imagePullPolicy,
227
+ imagePullPolicy: pullPolicy,
191
228
  ...(command && { command }),
192
229
  ...(args && { args }),
193
230
  ports: [{ containerPort: port }],
@@ -215,11 +252,14 @@ function WebService(props) {
215
252
  // Expose the app port directly (so consumers can reference it) while
216
253
  // keeping 80 as a stable backward-compatible alias: existing
217
254
  // Endpoints/default servicePort=80 users keep routing during
218
- // migration to explicit servicePort
255
+ // migration to explicit servicePort.
256
+ // Port names are REQUIRED whenever a Service has more than one port —
257
+ // without them the API server rejects the resource (caught by Flux
258
+ // dry-run as "spec.ports[i].name: Required value").
219
259
  ports: [
220
- { port, targetPort: port },
260
+ { name: 'http', port, targetPort: port },
221
261
  // eslint-disable-next-line -- 80 alias for legacy servicePort=80 consumers
222
- ...(port !== 80 ? [{ port: 80, targetPort: port }] : []),
262
+ ...(port !== 80 ? [{ name: 'http-80', port: 80, targetPort: port }] : []),
223
263
  ],
224
264
  },
225
265
  };